From 56c41a614a5cb5ddcbbc6235c622d162d81d0220 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 Feb 2020 17:38:50 +0300 Subject: [PATCH 001/961] Remove CommentsPage component --- .../Online/TestSceneCommentsContainer.cs | 3 +- .../Visual/Online/TestSceneCommentsPage.cs | 232 ------------------ .../Overlays/Comments/CommentsContainer.cs | 134 ++++++++-- osu.Game/Overlays/Comments/CommentsPage.cs | 161 ------------ 4 files changed, 112 insertions(+), 418 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs delete mode 100644 osu.Game/Overlays/Comments/CommentsPage.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index ece280659c..b9938ab25b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -27,8 +27,7 @@ namespace osu.Game.Tests.Visual.Online typeof(OverlaySortTabControl<>), typeof(ShowChildrenButton), typeof(DeletedCommentsCounter), - typeof(VotePill), - typeof(CommentsPage), + typeof(VotePill) }; protected override bool UseOnlineAPI => true; diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs deleted file mode 100644 index a28a0107a1..0000000000 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsPage.cs +++ /dev/null @@ -1,232 +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.Overlays.Comments; -using osu.Game.Overlays; -using osu.Framework.Allocation; -using osu.Game.Online.API.Requests.Responses; -using osu.Game.Users; -using osu.Game.Graphics.UserInterface; -using osu.Framework.Bindables; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics; -using osuTK; -using JetBrains.Annotations; -using NUnit.Framework; - -namespace osu.Game.Tests.Visual.Online -{ - public class TestSceneCommentsPage : OsuTestScene - { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(DrawableComment), - typeof(CommentsPage), - }; - - [Cached] - private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - - private readonly BindableBool showDeleted = new BindableBool(); - private readonly Container content; - - private TestCommentsPage commentsPage; - - public TestSceneCommentsPage() - { - Add(new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - RelativeSizeAxes = Axes.X, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 10), - Children = new Drawable[] - { - new Container - { - AutoSizeAxes = Axes.Y, - Width = 200, - Child = new OsuCheckbox - { - Current = showDeleted, - LabelText = @"Show Deleted" - } - }, - content = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - } - }); - } - - [Test] - public void TestAppendDuplicatedComment() - { - AddStep("Create page", () => createPage(getCommentBundle())); - AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10); - AddStep("Append existing comment", () => commentsPage?.AppendComments(getCommentSubBundle())); - AddAssert("Dictionary length is 10", () => commentsPage?.DictionaryLength == 10); - } - - [Test] - public void TestEmptyBundle() - { - AddStep("Create page", () => createPage(getEmptyCommentBundle())); - AddAssert("Dictionary length is 0", () => commentsPage?.DictionaryLength == 0); - } - - private void createPage(CommentBundle commentBundle) - { - commentsPage = null; - content.Clear(); - content.Add(commentsPage = new TestCommentsPage(commentBundle) - { - ShowDeleted = { BindTarget = showDeleted } - }); - } - - private CommentBundle getEmptyCommentBundle() => new CommentBundle - { - Comments = new List(), - }; - - private CommentBundle getCommentBundle() => new CommentBundle - { - Comments = new List - { - new Comment - { - Id = 1, - Message = "Simple test comment", - LegacyName = "TestUser1", - CreatedAt = DateTimeOffset.Now, - 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", - LegacyName = "TestUser2", - CreatedAt = DateTimeOffset.Now, - DeletedAt = DateTimeOffset.Now, - VotesCount = 5 - }, - new Comment - { - Id = 3, - Message = "This comment is a top level", - LegacyName = "TestUser3", - CreatedAt = DateTimeOffset.Now, - RepliesCount = 2, - }, - new Comment - { - Id = 4, - ParentId = 3, - Message = "And this is a reply", - RepliesCount = 1, - LegacyName = "TestUser1", - CreatedAt = DateTimeOffset.Now, - }, - new Comment - { - Id = 15, - ParentId = 4, - Message = "Reply to reply", - LegacyName = "TestUser1", - CreatedAt = DateTimeOffset.Now, - }, - new Comment - { - Id = 6, - ParentId = 3, - LegacyName = "TestUser11515", - CreatedAt = DateTimeOffset.Now, - DeletedAt = DateTimeOffset.Now, - }, - new Comment - { - Id = 5, - Message = "This comment is voted and edited", - LegacyName = "BigBrainUser", - CreatedAt = DateTimeOffset.Now, - EditedAt = DateTimeOffset.Now, - VotesCount = 1000, - EditedById = 1, - } - }, - IncludedComments = new List(), - UserVotes = new List - { - 5 - }, - Users = new List - { - new User - { - Id = 1, - Username = "Good_Admin" - } - }, - }; - - private CommentBundle getCommentSubBundle() => new CommentBundle - { - Comments = new List - { - new Comment - { - Id = 1, - Message = "Simple test comment", - LegacyName = "TestUser1", - CreatedAt = DateTimeOffset.Now, - VotesCount = 5 - }, - }, - IncludedComments = new List(), - }; - - private class TestCommentsPage : CommentsPage - { - public TestCommentsPage(CommentBundle commentBundle) - : base(commentBundle) - { - } - - public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle); - - public int DictionaryLength => CommentDictionary.Count; - } - } -} diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 591a9dc86e..ef833b9345 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -9,10 +9,12 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osu.Game.Online.API.Requests.Responses; -using System.Threading; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Users; +using System.Collections.Generic; +using JetBrains.Annotations; +using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Comments { @@ -30,7 +32,6 @@ namespace osu.Game.Overlays.Comments private IAPIProvider api { get; set; } private GetCommentsRequest request; - private CancellationTokenSource loadCancellation; private int currentPage; private FillFlowContainer content; @@ -151,9 +152,8 @@ namespace osu.Game.Overlays.Comments return; request?.Cancel(); - loadCancellation?.Cancel(); request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0); - request.Success += onSuccess; + request.Success += response => Schedule(() => onSuccess(response)); api.PerformAsync(request); } @@ -166,44 +166,132 @@ namespace osu.Game.Overlays.Comments content.Clear(); } + private readonly Dictionary commentDictionary = new Dictionary(); + private void onSuccess(CommentBundle response) { - loadCancellation = new CancellationTokenSource(); - - LoadComponentAsync(new CommentsPage(response) + if (!response.Comments.Any()) { - ShowDeleted = { BindTarget = ShowDeleted }, - Sort = { BindTarget = Sort }, - Type = { BindTarget = type }, - CommentableId = { BindTarget = id } - }, loaded => + content.Add(new NoCommentsPlaceholder()); + return; + } + else { - content.Add(loaded); + appendComments(response); deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); + } - if (response.HasMore) + if (response.HasMore) + { + int loadedTopLevelComments = 0; + content.Children.OfType().ForEach(p => loadedTopLevelComments++); + + moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; + moreButton.IsLoading = false; + } + else + { + moreButton.Hide(); + } + } + + /// + /// Appends retrieved comments to the subtree rooted of comments in this page. + /// + /// The bundle of comments to add. + private void appendComments([NotNull] CommentBundle bundle) + { + var orphaned = new List(); + + foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) + { + // Exclude possible duplicated comments. + if (commentDictionary.ContainsKey(comment.Id)) + continue; + + addNewComment(comment); + } + + // Comments whose parents were seen later than themselves can now be added. + foreach (var o in orphaned) + addNewComment(o); + + void addNewComment(Comment comment) + { + var drawableComment = getDrawableComment(comment); + + if (comment.ParentId == null) { - int loadedTopLevelComments = 0; - content.Children.OfType().ForEach(p => loadedTopLevelComments += p.Children.OfType().Count()); - - moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; - moreButton.IsLoading = false; + // Comments that have no parent are added as top-level comments to the flow. + content.Add(drawableComment); + } + else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) + { + // The comment's parent has already been seen, so the parent<-> child links can be added. + comment.ParentComment = parentDrawable.Comment; + parentDrawable.Replies.Add(drawableComment); } else { - moreButton.Hide(); + // The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order. + // Since this comment has now been seen, any further children can be added to it without being orphaned themselves. + orphaned.Add(comment); } + } + } - commentCounter.Current.Value = response.Total; - }, loadCancellation.Token); + private DrawableComment getDrawableComment(Comment comment) + { + if (commentDictionary.TryGetValue(comment.Id, out var existing)) + return existing; + + return commentDictionary[comment.Id] = new DrawableComment(comment) + { + ShowDeleted = { BindTarget = ShowDeleted }, + Sort = { BindTarget = Sort }, + RepliesRequested = onCommentRepliesRequested + }; + } + + private void onCommentRepliesRequested(DrawableComment drawableComment, int page) + { + var request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id); + + request.Success += response => Schedule(() => appendComments(response)); + + api.PerformAsync(request); } protected override void Dispose(bool isDisposing) { request?.Cancel(); - loadCancellation?.Cancel(); base.Dispose(isDisposing); } + + private class NoCommentsPlaceholder : CompositeDrawable + { + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + Height = 80; + RelativeSizeAxes = Axes.X; + AddRangeInternal(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4 + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 50 }, + Text = @"No comments yet." + } + }); + } + } } } diff --git a/osu.Game/Overlays/Comments/CommentsPage.cs b/osu.Game/Overlays/Comments/CommentsPage.cs deleted file mode 100644 index 9b146b0a7d..0000000000 --- a/osu.Game/Overlays/Comments/CommentsPage.cs +++ /dev/null @@ -1,161 +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.Containers; -using osu.Framework.Graphics; -using osu.Framework.Bindables; -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 JetBrains.Annotations; - -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; - private FillFlowContainer flow; - - public CommentsPage(CommentBundle commentBundle) - { - this.commentBundle = commentBundle; - } - - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - - AddRangeInternal(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5 - }, - flow = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - } - }); - - if (!commentBundle.Comments.Any()) - { - flow.Add(new NoCommentsPlaceholder()); - return; - } - - AppendComments(commentBundle); - } - - private DrawableComment getDrawableComment(Comment comment) - { - if (CommentDictionary.TryGetValue(comment.Id, out var existing)) - return existing; - - return CommentDictionary[comment.Id] = new DrawableComment(comment) - { - ShowDeleted = { BindTarget = ShowDeleted }, - Sort = { BindTarget = Sort }, - RepliesRequested = onCommentRepliesRequested - }; - } - - private void onCommentRepliesRequested(DrawableComment drawableComment, int page) - { - var request = new GetCommentsRequest(CommentableId.Value, Type.Value, Sort.Value, page, drawableComment.Comment.Id); - - request.Success += response => Schedule(() => AppendComments(response)); - - api.PerformAsync(request); - } - - protected readonly Dictionary CommentDictionary = new Dictionary(); - - /// - /// Appends retrieved comments to the subtree rooted of comments in this page. - /// - /// The bundle of comments to add. - protected void AppendComments([NotNull] CommentBundle bundle) - { - var orphaned = new List(); - - foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) - { - // Exclude possible duplicated comments. - if (CommentDictionary.ContainsKey(comment.Id)) - continue; - - addNewComment(comment); - } - - // Comments whose parents were seen later than themselves can now be added. - foreach (var o in orphaned) - addNewComment(o); - - void addNewComment(Comment comment) - { - var drawableComment = getDrawableComment(comment); - - if (comment.ParentId == null) - { - // Comments that have no parent are added as top-level comments to the flow. - flow.Add(drawableComment); - } - else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) - { - // The comment's parent has already been seen, so the parent<-> child links can be added. - comment.ParentComment = parentDrawable.Comment; - parentDrawable.Replies.Add(drawableComment); - } - else - { - // The comment's parent has not been seen yet, so keep it orphaned for the time being. This can occur if the comments arrive out of order. - // Since this comment has now been seen, any further children can be added to it without being orphaned themselves. - orphaned.Add(comment); - } - } - } - - private class NoCommentsPlaceholder : CompositeDrawable - { - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - Height = 80; - RelativeSizeAxes = Axes.X; - AddRangeInternal(new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4 - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 50 }, - Text = @"No comments yet." - } - }); - } - } - } -} From ae4f5cdf371fbc3d8be399e47bb440ce2cb0f39f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 Feb 2020 18:00:48 +0300 Subject: [PATCH 002/961] Add async loading support --- .../Overlays/Comments/CommentsContainer.cs | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index ef833b9345..988b8cc4d4 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Bindables; using osu.Framework.Graphics.Shapes; using osu.Game.Online.API.Requests.Responses; +using System.Threading; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Users; @@ -32,6 +33,7 @@ namespace osu.Game.Overlays.Comments private IAPIProvider api { get; set; } private GetCommentsRequest request; + private CancellationTokenSource loadCancellation; private int currentPage; private FillFlowContainer content; @@ -152,6 +154,7 @@ namespace osu.Game.Overlays.Comments return; request?.Cancel(); + loadCancellation?.Cancel(); request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0); request.Success += response => Schedule(() => onSuccess(response)); api.PerformAsync(request); @@ -164,6 +167,7 @@ namespace osu.Game.Overlays.Comments moreButton.Show(); moreButton.IsLoading = true; content.Clear(); + commentDictionary.Clear(); } private readonly Dictionary commentDictionary = new Dictionary(); @@ -173,26 +177,33 @@ namespace osu.Game.Overlays.Comments if (!response.Comments.Any()) { content.Add(new NoCommentsPlaceholder()); + moreButton.Hide(); return; } else { - appendComments(response); + var topLevelComments = appendComments(response); - deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); - } + LoadComponentsAsync(topLevelComments, loaded => + { + content.AddRange(loaded); - if (response.HasMore) - { - int loadedTopLevelComments = 0; - content.Children.OfType().ForEach(p => loadedTopLevelComments++); + deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); + commentCounter.Current.Value = response.Total; - moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; - moreButton.IsLoading = false; - } - else - { - moreButton.Hide(); + if (response.HasMore) + { + int loadedTopLevelComments = 0; + content.Children.OfType().ForEach(p => loadedTopLevelComments++); + + moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; + moreButton.IsLoading = false; + } + else + { + moreButton.Hide(); + } + }, (loadCancellation = new CancellationTokenSource()).Token); } } @@ -200,8 +211,9 @@ namespace osu.Game.Overlays.Comments /// Appends retrieved comments to the subtree rooted of comments in this page. /// /// The bundle of comments to add. - private void appendComments([NotNull] CommentBundle bundle) + private List appendComments([NotNull] CommentBundle bundle) { + var topLevelComments = new List(); var orphaned = new List(); foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) @@ -217,6 +229,8 @@ namespace osu.Game.Overlays.Comments foreach (var o in orphaned) addNewComment(o); + return topLevelComments; + void addNewComment(Comment comment) { var drawableComment = getDrawableComment(comment); @@ -224,7 +238,7 @@ namespace osu.Game.Overlays.Comments if (comment.ParentId == null) { // Comments that have no parent are added as top-level comments to the flow. - content.Add(drawableComment); + topLevelComments.Add(drawableComment); } else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) { @@ -266,6 +280,7 @@ namespace osu.Game.Overlays.Comments protected override void Dispose(bool isDisposing) { request?.Cancel(); + loadCancellation?.Cancel(); base.Dispose(isDisposing); } From de10e502782f337c1c37c3b88ac96a98f3eb0091 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 Feb 2020 18:31:01 +0300 Subject: [PATCH 003/961] Add test scene to test local comment bundles --- .../TestSceneOfflineCommentsContainer.cs | 177 ++++++++++++++++++ .../Overlays/Comments/CommentsContainer.cs | 16 +- 2 files changed, 185 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs new file mode 100644 index 0000000000..b69cc46bb8 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -0,0 +1,177 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Game.Overlays.Comments; +using osu.Game.Overlays; +using osu.Framework.Allocation; +using osu.Game.Online.API.Requests.Responses; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneOfflineCommentsContainer : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(CommentsContainer), + typeof(CommentsHeader), + typeof(DrawableComment), + typeof(HeaderButton), + typeof(OverlaySortTabControl<>), + typeof(ShowChildrenButton), + typeof(DeletedCommentsCounter), + typeof(VotePill) + }; + + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + + private TestCommentsContainer comments; + + [SetUp] + public void SetUp() => Schedule(() => + { + Clear(); + Add(new BasicScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = comments = new TestCommentsContainer() + }); + }); + + [Test] + public void TestLocalCommentBundle() + { + AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle())); + AddStep("Add empty comment bundle", () => comments.ShowComments(getEmptyCommentBundle())); + } + + private CommentBundle getEmptyCommentBundle() => new CommentBundle + { + Comments = new List(), + }; + + private CommentBundle getCommentBundle() => new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 1, + Message = "Simple test comment", + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + 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", + LegacyName = "TestUser2", + CreatedAt = DateTimeOffset.Now, + DeletedAt = DateTimeOffset.Now, + VotesCount = 5 + }, + new Comment + { + Id = 3, + Message = "This comment is a top level", + LegacyName = "TestUser3", + CreatedAt = DateTimeOffset.Now, + RepliesCount = 2, + }, + new Comment + { + Id = 4, + ParentId = 3, + Message = "And this is a reply", + RepliesCount = 1, + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + }, + new Comment + { + Id = 15, + ParentId = 4, + Message = "Reply to reply", + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + }, + new Comment + { + Id = 6, + ParentId = 3, + LegacyName = "TestUser11515", + CreatedAt = DateTimeOffset.Now, + DeletedAt = DateTimeOffset.Now, + }, + new Comment + { + Id = 5, + Message = "This comment is voted and edited", + LegacyName = "BigBrainUser", + CreatedAt = DateTimeOffset.Now, + EditedAt = DateTimeOffset.Now, + VotesCount = 1000, + EditedById = 1, + } + }, + IncludedComments = new List(), + UserVotes = new List + { + 5 + }, + Users = new List + { + new User + { + Id = 1, + Username = "Good_Admin" + } + }, + Total = 10 + }; + + private class TestCommentsContainer : CommentsContainer + { + public void ShowComments(CommentBundle bundle) + { + CommentCounter.Current.Value = 0; + ClearComments(); + OnSuccess(bundle); + } + } + } +} diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 988b8cc4d4..00aa74f9ac 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Comments private FillFlowContainer content; private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; - private TotalCommentsCounter commentCounter; + protected TotalCommentsCounter CommentCounter; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -60,7 +60,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - commentCounter = new TotalCommentsCounter(), + CommentCounter = new TotalCommentsCounter(), new CommentsHeader { Sort = { BindTarget = Sort }, @@ -137,14 +137,14 @@ namespace osu.Game.Overlays.Comments return; // only reset when changing ID/type. other refetch ops are generally just changing sort order. - commentCounter.Current.Value = 0; + CommentCounter.Current.Value = 0; refetchComments(); } private void refetchComments() { - clearComments(); + ClearComments(); getComments(); } @@ -156,11 +156,11 @@ namespace osu.Game.Overlays.Comments request?.Cancel(); loadCancellation?.Cancel(); request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, currentPage++, 0); - request.Success += response => Schedule(() => onSuccess(response)); + request.Success += response => Schedule(() => OnSuccess(response)); api.PerformAsync(request); } - private void clearComments() + protected void ClearComments() { currentPage = 1; deletedCommentsCounter.Count.Value = 0; @@ -172,7 +172,7 @@ namespace osu.Game.Overlays.Comments private readonly Dictionary commentDictionary = new Dictionary(); - private void onSuccess(CommentBundle response) + protected void OnSuccess(CommentBundle response) { if (!response.Comments.Any()) { @@ -189,7 +189,7 @@ namespace osu.Game.Overlays.Comments content.AddRange(loaded); deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); - commentCounter.Current.Value = response.Total; + CommentCounter.Current.Value = response.Total; if (response.HasMore) { From 1166d3d69624bad7e6ed645d5a5ac1c53201a92e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 Feb 2020 18:52:58 +0300 Subject: [PATCH 004/961] CI fixes --- .../Overlays/Comments/CommentsContainer.cs | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 00aa74f9ac..da2cdbc335 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -180,31 +180,29 @@ namespace osu.Game.Overlays.Comments moreButton.Hide(); return; } - else + + var topLevelComments = appendComments(response); + + LoadComponentsAsync(topLevelComments, loaded => { - var topLevelComments = appendComments(response); + content.AddRange(loaded); - LoadComponentsAsync(topLevelComments, loaded => + deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); + CommentCounter.Current.Value = response.Total; + + if (response.HasMore) { - content.AddRange(loaded); + int loadedTopLevelComments = 0; + content.Children.OfType().ForEach(p => loadedTopLevelComments++); - deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); - CommentCounter.Current.Value = response.Total; - - if (response.HasMore) - { - int loadedTopLevelComments = 0; - content.Children.OfType().ForEach(p => loadedTopLevelComments++); - - moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; - moreButton.IsLoading = false; - } - else - { - moreButton.Hide(); - } - }, (loadCancellation = new CancellationTokenSource()).Token); - } + moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; + moreButton.IsLoading = false; + } + else + { + moreButton.Hide(); + } + }, (loadCancellation = new CancellationTokenSource()).Token); } /// @@ -270,11 +268,11 @@ namespace osu.Game.Overlays.Comments private void onCommentRepliesRequested(DrawableComment drawableComment, int page) { - var request = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id); + var req = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id); - request.Success += response => Schedule(() => appendComments(response)); + req.Success += response => Schedule(() => appendComments(response)); - api.PerformAsync(request); + api.PerformAsync(req); } protected override void Dispose(bool isDisposing) From 638d0601451c88872c727baf5c9cc653fcb5b7ec Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 26 Feb 2020 18:55:43 +0300 Subject: [PATCH 005/961] Fix incorrect character on RepliesButton --- 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 cb9e32f1ad..46f600615a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -384,7 +384,7 @@ namespace osu.Game.Overlays.Comments protected override void OnExpandedChanged(ValueChangedEvent expanded) { - text.Text = $@"{(expanded.NewValue ? "[+]" : "[-]")} replies ({count})"; + text.Text = $@"{(expanded.NewValue ? "[-]" : "[+]")} replies ({count})"; } } From ddb494efb39d154d0dfae81fbd488395bbd5a16c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 27 Feb 2020 01:38:21 +0300 Subject: [PATCH 006/961] Add back regression test --- .../TestSceneOfflineCommentsContainer.cs | 29 +++++++++++++++++++ .../Overlays/Comments/CommentsContainer.cs | 18 ++++++------ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index b69cc46bb8..4040f36ef8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -51,6 +51,15 @@ namespace osu.Game.Tests.Visual.Online AddStep("Add empty comment bundle", () => comments.ShowComments(getEmptyCommentBundle())); } + [Test] + public void TestAppendDuplicatedComment() + { + AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle())); + AddUntilStep("Dictionary length is 10", () => comments.DictionaryLength == 10); + AddStep("Append existing comment", () => comments.AppendComments(getCommentSubBundle())); + AddAssert("Dictionary length is 10", () => comments.DictionaryLength == 10); + } + private CommentBundle getEmptyCommentBundle() => new CommentBundle { Comments = new List(), @@ -164,8 +173,28 @@ namespace osu.Game.Tests.Visual.Online Total = 10 }; + private CommentBundle getCommentSubBundle() => new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 1, + Message = "Simple test comment", + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + VotesCount = 5 + }, + }, + IncludedComments = new List(), + }; + private class TestCommentsContainer : CommentsContainer { + public int DictionaryLength => CommentDictionary.Count; + + public new void AppendComments(CommentBundle bundle) => base.AppendComments(bundle); + public void ShowComments(CommentBundle bundle) { CommentCounter.Current.Value = 0; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index da2cdbc335..0381d73583 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -167,10 +167,10 @@ namespace osu.Game.Overlays.Comments moreButton.Show(); moreButton.IsLoading = true; content.Clear(); - commentDictionary.Clear(); + CommentDictionary.Clear(); } - private readonly Dictionary commentDictionary = new Dictionary(); + protected readonly Dictionary CommentDictionary = new Dictionary(); protected void OnSuccess(CommentBundle response) { @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.Comments return; } - var topLevelComments = appendComments(response); + var topLevelComments = AppendComments(response); LoadComponentsAsync(topLevelComments, loaded => { @@ -209,7 +209,7 @@ namespace osu.Game.Overlays.Comments /// Appends retrieved comments to the subtree rooted of comments in this page. /// /// The bundle of comments to add. - private List appendComments([NotNull] CommentBundle bundle) + protected List AppendComments([NotNull] CommentBundle bundle) { var topLevelComments = new List(); var orphaned = new List(); @@ -217,7 +217,7 @@ namespace osu.Game.Overlays.Comments foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) { // Exclude possible duplicated comments. - if (commentDictionary.ContainsKey(comment.Id)) + if (CommentDictionary.ContainsKey(comment.Id)) continue; addNewComment(comment); @@ -238,7 +238,7 @@ namespace osu.Game.Overlays.Comments // Comments that have no parent are added as top-level comments to the flow. topLevelComments.Add(drawableComment); } - else if (commentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) + else if (CommentDictionary.TryGetValue(comment.ParentId.Value, out var parentDrawable)) { // The comment's parent has already been seen, so the parent<-> child links can be added. comment.ParentComment = parentDrawable.Comment; @@ -255,10 +255,10 @@ namespace osu.Game.Overlays.Comments private DrawableComment getDrawableComment(Comment comment) { - if (commentDictionary.TryGetValue(comment.Id, out var existing)) + if (CommentDictionary.TryGetValue(comment.Id, out var existing)) return existing; - return commentDictionary[comment.Id] = new DrawableComment(comment) + return CommentDictionary[comment.Id] = new DrawableComment(comment) { ShowDeleted = { BindTarget = ShowDeleted }, Sort = { BindTarget = Sort }, @@ -270,7 +270,7 @@ namespace osu.Game.Overlays.Comments { var req = new GetCommentsRequest(id.Value, type.Value, Sort.Value, page, drawableComment.Comment.Id); - req.Success += response => Schedule(() => appendComments(response)); + req.Success += response => Schedule(() => AppendComments(response)); api.PerformAsync(req); } From 02fd85d485f232745df6296e30d56da410ec66cd Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 27 Feb 2020 01:42:55 +0300 Subject: [PATCH 007/961] CI fix --- .../TestSceneOfflineCommentsContainer.cs | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 4040f36ef8..1ba8bbf7c4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -11,6 +11,7 @@ using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; +using JetBrains.Annotations; namespace osu.Game.Tests.Visual.Online { @@ -44,13 +45,6 @@ namespace osu.Game.Tests.Visual.Online }); }); - [Test] - public void TestLocalCommentBundle() - { - AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle())); - AddStep("Add empty comment bundle", () => comments.ShowComments(getEmptyCommentBundle())); - } - [Test] public void TestAppendDuplicatedComment() { @@ -60,6 +54,13 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Dictionary length is 10", () => comments.DictionaryLength == 10); } + [Test] + public void TestLocalCommentBundle() + { + AddStep("Add comment bundle", () => comments.ShowComments(getCommentBundle())); + AddStep("Add empty comment bundle", () => comments.ShowComments(getEmptyCommentBundle())); + } + private CommentBundle getEmptyCommentBundle() => new CommentBundle { Comments = new List(), @@ -175,25 +176,25 @@ namespace osu.Game.Tests.Visual.Online private CommentBundle getCommentSubBundle() => new CommentBundle { - Comments = new List - { - new Comment - { - Id = 1, - Message = "Simple test comment", - LegacyName = "TestUser1", - CreatedAt = DateTimeOffset.Now, - VotesCount = 5 - }, - }, - IncludedComments = new List(), + Comments = new List + { + new Comment + { + Id = 1, + Message = "Simple test comment", + LegacyName = "TestUser1", + CreatedAt = DateTimeOffset.Now, + VotesCount = 5 + }, + }, + IncludedComments = new List(), }; private class TestCommentsContainer : CommentsContainer { - public int DictionaryLength => CommentDictionary.Count; + public new void AppendComments([NotNull] CommentBundle bundle) => base.AppendComments(bundle); - public new void AppendComments(CommentBundle bundle) => base.AppendComments(bundle); + public int DictionaryLength => CommentDictionary.Count; public void ShowComments(CommentBundle bundle) { From e2c495e8c28412d2d3fa2f530fc8409f516e54ce Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Thu, 27 Feb 2020 20:00:41 +0300 Subject: [PATCH 008/961] Move drawables loading to AppendComments() --- .../Overlays/Comments/CommentsContainer.cs | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 0381d73583..f7bf1e2b07 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -174,6 +174,8 @@ namespace osu.Game.Overlays.Comments protected void OnSuccess(CommentBundle response) { + CommentCounter.Current.Value = response.Total; + if (!response.Comments.Any()) { content.Add(new NoCommentsPlaceholder()); @@ -181,35 +183,14 @@ namespace osu.Game.Overlays.Comments return; } - var topLevelComments = AppendComments(response); - - LoadComponentsAsync(topLevelComments, loaded => - { - content.AddRange(loaded); - - deletedCommentsCounter.Count.Value += response.Comments.Count(c => c.IsDeleted && c.IsTopLevel); - CommentCounter.Current.Value = response.Total; - - if (response.HasMore) - { - int loadedTopLevelComments = 0; - content.Children.OfType().ForEach(p => loadedTopLevelComments++); - - moreButton.Current.Value = response.TopLevelCount - loadedTopLevelComments; - moreButton.IsLoading = false; - } - else - { - moreButton.Hide(); - } - }, (loadCancellation = new CancellationTokenSource()).Token); + AppendComments(response); } /// /// Appends retrieved comments to the subtree rooted of comments in this page. /// /// The bundle of comments to add. - protected List AppendComments([NotNull] CommentBundle bundle) + protected void AppendComments([NotNull] CommentBundle bundle) { var topLevelComments = new List(); var orphaned = new List(); @@ -227,7 +208,28 @@ namespace osu.Game.Overlays.Comments foreach (var o in orphaned) addNewComment(o); - return topLevelComments; + if (topLevelComments.Any()) + { + LoadComponentsAsync(topLevelComments, loaded => + { + content.AddRange(loaded); + + deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel); + + if (bundle.HasMore) + { + int loadedTopLevelComments = 0; + content.Children.OfType().ForEach(p => loadedTopLevelComments++); + + moreButton.Current.Value = bundle.TopLevelCount - loadedTopLevelComments; + moreButton.IsLoading = false; + } + else + { + moreButton.Hide(); + } + }, (loadCancellation = new CancellationTokenSource()).Token); + } void addNewComment(Comment comment) { From 560a0174dff62173c2288a390a0324b9ddedfaf2 Mon Sep 17 00:00:00 2001 From: PercyDan54 <50285552+PercyDan54@users.noreply.github.com> Date: Fri, 18 Dec 2020 17:49:17 +0800 Subject: [PATCH 009/961] Make auto restart toggleable --- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index ae71041a64..466fdccfb7 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -2,7 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -20,9 +22,11 @@ namespace osu.Game.Rulesets.Mods public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; + [SettingSource("Restart on fail", "Automatically restarts when failed.")] + public BindableBool Restart { get; } = new BindableBool(); public bool PerformFail() => true; - public bool RestartOnFail => true; + public bool RestartOnFail => Restart.Value; public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { From 2babb7ecb0b122555a339809ce158b748f0e3295 Mon Sep 17 00:00:00 2001 From: PercyDan54 <50285552+PercyDan54@users.noreply.github.com> Date: Fri, 18 Dec 2020 18:33:38 +0800 Subject: [PATCH 010/961] Fix CI --- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 466fdccfb7..925844275b 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Mods [SettingSource("Restart on fail", "Automatically restarts when failed.")] public BindableBool Restart { get; } = new BindableBool(); + public bool PerformFail() => true; public bool RestartOnFail => Restart.Value; From 33615646bd6ff48c2894d73c34a8e66fcb8eef84 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 18:10:40 +0900 Subject: [PATCH 011/961] Rename DrawableRoom test scene --- .../{TestSceneRoomStatus.cs => TestSceneDrawableRoom.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename osu.Game.Tests/Visual/Multiplayer/{TestSceneRoomStatus.cs => TestSceneDrawableRoom.cs} (95%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs similarity index 95% rename from osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs rename to osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index cec40635f3..1231e0f7d0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -10,9 +10,9 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.Multiplayer { - public class TestSceneRoomStatus : OsuTestScene + public class TestSceneDrawableRoom : OsuTestScene { - public TestSceneRoomStatus() + public TestSceneDrawableRoom() { Child = new FillFlowContainer { From 1a832a4e6bb3dfd64587a7872fa841318a20006f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 18:23:37 +0900 Subject: [PATCH 012/961] Add clickability to test --- .../Multiplayer/TestSceneDrawableRoom.cs | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 1231e0f7d0..532ce6790f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.OnlinePlay.Lounge.Components; @@ -20,32 +21,44 @@ namespace osu.Game.Tests.Visual.Multiplayer Width = 0.5f, Children = new Drawable[] { - new DrawableRoom(new Room + createDrawableRoom(new Room { Name = { Value = "Open - ending in 1 day" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } - }) { MatchingFilter = true }, - new DrawableRoom(new Room + }), + createDrawableRoom(new Room { Name = { Value = "Playing - ending in 1 day" }, Status = { Value = new RoomStatusPlaying() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } - }) { MatchingFilter = true }, - new DrawableRoom(new Room + }), + createDrawableRoom(new Room { Name = { Value = "Ended" }, Status = { Value = new RoomStatusEnded() }, EndDate = { Value = DateTimeOffset.Now } - }) { MatchingFilter = true }, - new DrawableRoom(new Room + }), + createDrawableRoom(new Room { Name = { Value = "Open" }, Status = { Value = new RoomStatusOpen() }, Category = { Value = RoomCategory.Realtime } - }) { MatchingFilter = true }, + }), } }; } + + private DrawableRoom createDrawableRoom(Room room) + { + var drawableRoom = new DrawableRoom(room) + { + MatchingFilter = true + }; + + drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected; + + return drawableRoom; + } } } From c50e3fd31778c3ac476742d6e5897d586980c42b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 18:24:06 +0900 Subject: [PATCH 013/961] Clean up selection box construction --- .../Lounge/Components/DrawableRoom.cs | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 35782c6104..14fd715b69 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public event Action StateChanged; - private readonly Box selectionBox; + private Box selectionBox; [Resolved(canBeNull: true)] private OnlinePlayScreen parentScreen { get; set; } @@ -55,14 +55,18 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components get => state; set { - if (value == state) return; + if (value == state) + return; state = value; - if (state == SelectionState.Selected) - selectionBox.FadeIn(transition_duration); - else - selectionBox.FadeOut(transition_duration); + if (selectionBox != null) + { + if (state == SelectionState.Selected) + selectionBox.FadeIn(transition_duration); + else + selectionBox.FadeOut(transition_duration); + } StateChanged?.Invoke(State); } @@ -99,13 +103,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Height = height + SELECTION_BORDER_WIDTH * 2; CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2; Masking = true; - - // create selectionBox here so State can be set before being loaded - selectionBox = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0f, - }; } [BackgroundDependencyLoader] @@ -118,7 +115,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new StatusColouredContainer(transition_duration) { RelativeSizeAxes = Axes.Both, - Child = selectionBox + Child = selectionBox = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = state == SelectionState.Selected ? 1 : 0, + } }, new Container { From 14b6949456b2f7d7278839c9e40bb7a8b49956c0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 18:50:05 +0900 Subject: [PATCH 014/961] Shorten room status messages --- osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs | 2 +- osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs | 2 +- osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs index c852f86f6b..01f3ae368b 100644 --- a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusEnded.cs @@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusEnded : RoomStatus { - public override string Message => @"Ended"; + public override string Message => "Ended"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDarker; } } diff --git a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs index 4f7f0d6f5d..686d4f4033 100644 --- a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusOpen.cs @@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusOpen : RoomStatus { - public override string Message => @"Welcoming Players"; + public override string Message => "Open"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.GreenLight; } } diff --git a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs index f04f1b23af..83f1acf52a 100644 --- a/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs +++ b/osu.Game/Online/Rooms/RoomStatuses/RoomStatusPlaying.cs @@ -8,7 +8,7 @@ namespace osu.Game.Online.Rooms.RoomStatuses { public class RoomStatusPlaying : RoomStatus { - public override string Message => @"Now Playing"; + public override string Message => "Playing"; public override Color4 GetAppropriateColour(OsuColour colours) => colours.Purple; } } From 2ddfa15a80d0c6ea11c2fdb0d8499557e21565f8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 18:50:27 +0900 Subject: [PATCH 015/961] Redesign RoomStatusInfo --- .../OnlinePlay/Components/RoomStatusInfo.cs | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs index bcc256bcff..900dea1e8c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs @@ -4,12 +4,16 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Components { @@ -23,26 +27,28 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - StatusPart statusPart; + StatusPill statusPill; EndDatePart endDatePart; InternalChild = new FillFlowContainer { AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2), Children = new Drawable[] { - statusPart = new StatusPart + statusPill = new StatusPill(), + endDatePart = new EndDatePart { - Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14) - }, - endDatePart = new EndDatePart { Font = OsuFont.GetFont(size: 14) } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12) + } } }; - statusPart.EndDate.BindTo(EndDate); - statusPart.Status.BindTo(Status); - statusPart.Availability.BindTo(Availability); + statusPill.EndDate.BindTo(EndDate); + statusPill.Status.BindTo(Status); endDatePart.EndDate.BindTo(EndDate); } @@ -80,37 +86,49 @@ namespace osu.Game.Screens.OnlinePlay.Components } } - private class StatusPart : EndDatePart + private class StatusPill : CompositeDrawable { + public readonly IBindable EndDate = new Bindable(); public readonly IBindable Status = new Bindable(); - public readonly IBindable Availability = new Bindable(); [Resolved] private OsuColour colours { get; set; } - public StatusPart() + private Drawable background; + private SpriteText statusText; + + [BackgroundDependencyLoader] + private void load() { - EndDate.BindValueChanged(_ => Format()); - Status.BindValueChanged(_ => Format()); - Availability.BindValueChanged(_ => Format()); + Size = new Vector2(60, 16); + + InternalChildren = new[] + { + background = new Circle { RelativeSizeAxes = Axes.Both }, + statusText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), + Colour = Color4.Black + } + }; } protected override void LoadComplete() { base.LoadComplete(); - Text = Format(); + EndDate.BindValueChanged(_ => updateDisplay()); + Status.BindValueChanged(_ => updateDisplay(), true); } - protected override string Format() + private void updateDisplay() { - if (!IsLoaded) - return string.Empty; + RoomStatus status = EndDate.Value < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); - RoomStatus status = Date < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); - - this.FadeColour(status.GetAppropriateColour(colours), 100); - return $"{Availability.Value.GetDescription()}, {status.Message}"; + background.FadeColour(status.GetAppropriateColour(colours), 100); + statusText.Text = status.Message; } } } From 8929aa0ca70ca397e5f05c3a0157e68af3136c68 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 6 Jul 2021 20:04:32 +0900 Subject: [PATCH 016/961] Initial redesign of DrawableRoom --- .../Multiplayer/TestSceneDrawableRoom.cs | 14 ++- .../Lounge/Components/DrawableRoom.cs | 104 ++++++++---------- 2 files changed, 57 insertions(+), 61 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 532ce6790f..7fef5aba4d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -8,6 +8,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osuTK; namespace osu.Game.Tests.Visual.Multiplayer { @@ -17,31 +18,34 @@ namespace osu.Game.Tests.Visual.Multiplayer { Child = new FillFlowContainer { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, - Width = 0.5f, + Size = new Vector2(0.9f), + Spacing = new Vector2(10), Children = new Drawable[] { createDrawableRoom(new Room { - Name = { Value = "Open - ending in 1 day" }, + Name = { Value = "Room name: Open - ending in 1 day" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } }), createDrawableRoom(new Room { - Name = { Value = "Playing - ending in 1 day" }, + Name = { Value = "Room name: Playing - ending in 1 day" }, Status = { Value = new RoomStatusPlaying() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) } }), createDrawableRoom(new Room { - Name = { Value = "Ended" }, + Name = { Value = "Room name: Ended" }, Status = { Value = new RoomStatusEnded() }, EndDate = { Value = DateTimeOffset.Now } }), createDrawableRoom(new Room { - Name = { Value = "Open" }, + Name = { Value = "Room name: Open" }, Status = { Value = new RoomStatusOpen() }, Category = { Value = RoomCategory.Realtime } }), diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 14fd715b69..062b83b66c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -8,6 +8,7 @@ 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.Effects; @@ -29,16 +30,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public class DrawableRoom : OsuClickableContainer, IStateful, IFilterable, IHasContextMenu { public const float SELECTION_BORDER_WIDTH = 4; - private const float corner_radius = 5; + private const float corner_radius = 10; private const float transition_duration = 60; - private const float content_padding = 10; - private const float height = 110; - private const float side_strip_width = 5; - private const float cover_width = 145; + private const float height = 100; public event Action StateChanged; - private Box selectionBox; + private Drawable selectionBox; [Resolved(canBeNull: true)] private OnlinePlayScreen parentScreen { get; set; } @@ -108,23 +106,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [BackgroundDependencyLoader] private void load(OsuColour colours) { - float stripWidth = side_strip_width * (Room.Category.Value == RoomCategory.Spotlight ? 2 : 1); - Children = new Drawable[] { - new StatusColouredContainer(transition_duration) - { - RelativeSizeAxes = Axes.Both, - Child = selectionBox = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = state == SelectionState.Selected ? 1 : 0, - } - }, new Container { + Name = @"Room content", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(SELECTION_BORDER_WIDTH), Child = new Container { RelativeSizeAxes = Axes.Both, @@ -141,69 +128,74 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"212121"), - }, - new StatusColouredContainer(transition_duration) - { - RelativeSizeAxes = Axes.Y, - Width = stripWidth, - Child = new Box { RelativeSizeAxes = Axes.Both } + Colour = Color4Extensions.FromHex(@"#27302E"), }, new Container { - RelativeSizeAxes = Axes.Y, - Width = cover_width, - Masking = true, - Margin = new MarginPadding { Left = stripWidth }, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + }, new Container { + Name = @"Left details", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Vertical = content_padding, - Left = stripWidth + cover_width + content_padding, - Right = content_padding, + Left = 20, + Vertical = 5 }, Children = new Drawable[] { - new FillFlowContainer + new RoomStatusInfo(), + new RoomName { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(5f), - Children = new Drawable[] - { - new RoomName { Font = OsuFont.GetFont(size: 18) }, - new ParticipantInfo(), - }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(size: 28) }, new FillFlowContainer { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 5), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, Children = new Drawable[] { - new RoomStatusInfo(), - new BeatmapTitle { TextSize = 14 }, - }, - }, - new ModeTypeInfo - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight, - }, - }, + new StarRatingRangeDisplay { Scale = new Vector2(0.85f) } + } + } + } }, }, }, }, + new StatusColouredContainer(transition_duration) + { + RelativeSizeAxes = Axes.Both, + Child = selectionBox = new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = state == SelectionState.Selected ? 1 : 0, + Masking = true, + CornerRadius = corner_radius, + BorderThickness = SELECTION_BORDER_WIDTH, + BorderColour = Color4.White, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, }; } From b4b0b862ef98c9ec300ba97a5a45d2b8de345a20 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 14:07:21 +0900 Subject: [PATCH 017/961] Adjust some layout --- .../OnlinePlay/Components/RoomStatusInfo.cs | 2 +- .../Lounge/Components/DrawableRoom.cs | 30 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs index 900dea1e8c..adb823c68a 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs @@ -34,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Components { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(2), + Spacing = new Vector2(4), Children = new Drawable[] { statusPill = new StatusPill(), diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 062b83b66c..8eb3f24b0d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -98,7 +98,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Room = room; RelativeSizeAxes = Axes.X; - Height = height + SELECTION_BORDER_WIDTH * 2; + Height = height; CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2; Masking = true; } @@ -125,11 +125,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), - }, new Container { Anchor = Anchor.CentreRight, @@ -138,10 +133,29 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components FillMode = FillMode.Fill, Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } }, - new Box + new GridContainer { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, 0.2f) + }, + Content = new[] + { + new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + }, + } + } }, new Container { From 185e36bf97f1cf670be5f56340c8e4f44ce90cb6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 15:11:07 +0900 Subject: [PATCH 018/961] Split pill display into abstract class --- .../OnlinePlay/Components/EndDateInfo.cs | 65 +++++++++ .../OnlinePlay/Components/RoomInfoPill.cs | 78 ++++++++++ .../OnlinePlay/Components/RoomStatusInfo.cs | 135 ------------------ .../OnlinePlay/Components/RoomStatusPill.cs | 54 +++++++ .../Lounge/Components/DrawableRoom.cs | 13 +- .../OnlinePlay/Lounge/Components/RoomInfo.cs | 4 +- 6 files changed, 211 insertions(+), 138 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs create mode 100644 osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs create mode 100644 osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs diff --git a/osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs b/osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs new file mode 100644 index 0000000000..3f93279461 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs @@ -0,0 +1,65 @@ +// 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.Game.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public class EndDateInfo : OnlinePlayComposite + { + public EndDateInfo() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new EndDatePart + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), + EndDate = { BindTarget = EndDate } + }; + } + + private class EndDatePart : DrawableDate + { + public readonly IBindable EndDate = new Bindable(); + + public EndDatePart() + : base(DateTimeOffset.UtcNow) + { + EndDate.BindValueChanged(date => + { + // If null, set a very large future date to prevent unnecessary schedules. + Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1); + }, true); + } + + protected override string Format() + { + if (EndDate.Value == null) + return string.Empty; + + var diffToNow = Date.Subtract(DateTimeOffset.Now); + + if (diffToNow.TotalSeconds < -5) + return $"Closed {base.Format()}"; + + if (diffToNow.TotalSeconds < 0) + return "Closed"; + + if (diffToNow.TotalSeconds < 5) + return "Closing soon"; + + return $"Closing {base.Format()}"; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs b/osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs new file mode 100644 index 0000000000..55de75cbcd --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs @@ -0,0 +1,78 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + /// + /// Abstract class for "pill" components displayed as part of s. + /// + public abstract class RoomInfoPill : OnlinePlayComposite + { + private const float padding = 8; + + protected Drawable Background { get; private set; } + + protected RoomInfoPill() + { + AutoSizeAxes = Axes.X; + Height = 16; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Masking = true, + Children = new[] + { + Background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.5f + }, + new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = padding }, + Child = new GridContainer + { + AutoSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize, minSize: 80 - 2 * padding) + }, + Content = new[] + { + new[] + { + CreateContent().With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + }) + } + } + } + } + } + }; + } + + protected abstract Drawable CreateContent(); + } +} diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs deleted file mode 100644 index adb823c68a..0000000000 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusInfo.cs +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Rooms; -using osu.Game.Online.Rooms.RoomStatuses; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.OnlinePlay.Components -{ - public class RoomStatusInfo : OnlinePlayComposite - { - public RoomStatusInfo() - { - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader] - private void load() - { - StatusPill statusPill; - EndDatePart endDatePart; - - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - statusPill = new StatusPill(), - endDatePart = new EndDatePart - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12) - } - } - }; - - statusPill.EndDate.BindTo(EndDate); - statusPill.Status.BindTo(Status); - endDatePart.EndDate.BindTo(EndDate); - } - - private class EndDatePart : DrawableDate - { - public readonly IBindable EndDate = new Bindable(); - - public EndDatePart() - : base(DateTimeOffset.UtcNow) - { - EndDate.BindValueChanged(date => - { - // If null, set a very large future date to prevent unnecessary schedules. - Date = date.NewValue ?? DateTimeOffset.Now.AddYears(1); - }, true); - } - - protected override string Format() - { - if (EndDate.Value == null) - return string.Empty; - - var diffToNow = Date.Subtract(DateTimeOffset.Now); - - if (diffToNow.TotalSeconds < -5) - return $"Closed {base.Format()}"; - - if (diffToNow.TotalSeconds < 0) - return "Closed"; - - if (diffToNow.TotalSeconds < 5) - return "Closing soon"; - - return $"Closing {base.Format()}"; - } - } - - private class StatusPill : CompositeDrawable - { - public readonly IBindable EndDate = new Bindable(); - public readonly IBindable Status = new Bindable(); - - [Resolved] - private OsuColour colours { get; set; } - - private Drawable background; - private SpriteText statusText; - - [BackgroundDependencyLoader] - private void load() - { - Size = new Vector2(60, 16); - - InternalChildren = new[] - { - background = new Circle { RelativeSizeAxes = Axes.Both }, - statusText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), - Colour = Color4.Black - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - EndDate.BindValueChanged(_ => updateDisplay()); - Status.BindValueChanged(_ => updateDisplay(), true); - } - - private void updateDisplay() - { - RoomStatus status = EndDate.Value < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); - - background.FadeColour(status.GetAppropriateColour(colours), 100); - statusText.Text = status.Message; - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs new file mode 100644 index 0000000000..6d9e84d618 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Rooms; +using osu.Game.Online.Rooms.RoomStatuses; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + /// + /// A pill that displays the room's current status. + /// + public class RoomStatusPill : RoomInfoPill + { + [Resolved] + private OsuColour colours { get; set; } + + private bool firstDisplay = true; + private SpriteText statusText; + + protected override void LoadComplete() + { + base.LoadComplete(); + + EndDate.BindValueChanged(_ => updateDisplay()); + Status.BindValueChanged(_ => updateDisplay(), true); + } + + private void updateDisplay() + { + RoomStatus status = EndDate.Value < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); + + Background.Alpha = 1; + Background.FadeColour(status.GetAppropriateColour(colours), firstDisplay ? 0 : 100); + statusText.Text = status.Message; + + firstDisplay = false; + } + + protected override Drawable CreateContent() => statusText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), + Colour = Color4.Black + }; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 8eb3f24b0d..56b3cfa11c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -181,9 +181,20 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Origin = Anchor.BottomLeft, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), Children = new Drawable[] { - new StarRatingRangeDisplay { Scale = new Vector2(0.85f) } + new PlaylistInfoPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new StarRatingRangeDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Scale = new Vector2(0.85f) + } } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs index a0a7f2dc28..819e19ad1e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components AutoSizeAxes = Axes.Y; RoomLocalUserInfo localUserInfo; - RoomStatusInfo statusInfo; + EndDateInfo statusInfo; ModeTypeInfo typeInfo; ParticipantInfo participantInfo; @@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components AutoSizeAxes = Axes.Y, Children = new Drawable[] { - statusInfo = new RoomStatusInfo(), + statusInfo = new EndDateInfo(), typeInfo = new ModeTypeInfo { Anchor = Anchor.BottomRight, From a8cbffa57ea5620fc18e8095d6a4e61ee780a9fc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 15:11:53 +0900 Subject: [PATCH 019/961] Add playlist count pill --- .../Components/PlaylistCountPill.cs | 39 +++++++++++++++++++ .../Lounge/Components/DrawableRoom.cs | 22 ++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs new file mode 100644 index 0000000000..7a4a638c2a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.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.Collections.Specialized; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + /// + /// A pill that displays the playlist item count. + /// + public class PlaylistCountPill : RoomInfoPill + { + private OsuTextFlowContainer count; + + protected override void LoadComplete() + { + base.LoadComplete(); + + Playlist.BindCollectionChanged(updateCount, true); + } + + private void updateCount(object sender, NotifyCollectionChangedEventArgs e) + { + count.Clear(); + count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); + count.AddText(" Maps"); + } + + protected override Drawable CreateContent() => count = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12)) + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 56b3cfa11c..b795b74e04 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -168,7 +168,25 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { - new RoomStatusInfo(), + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), + Children = new Drawable[] + { + new RoomStatusPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new EndDateInfo + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + } + }, new RoomName { Anchor = Anchor.CentreLeft, @@ -184,7 +202,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Spacing = new Vector2(4), Children = new Drawable[] { - new PlaylistInfoPill + new PlaylistCountPill { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From 435b4b0e6ed4400125d1e6ce512b76237dc15ff9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 15:18:38 +0900 Subject: [PATCH 020/961] Remove pill inheritance --- .../{RoomInfoPill.cs => PillContainer.cs} | 27 +++++++------- .../Components/PlaylistCountPill.cs | 29 ++++++++++----- .../OnlinePlay/Components/RoomStatusPill.cs | 35 +++++++++++++------ 3 files changed, 57 insertions(+), 34 deletions(-) rename osu.Game/Screens/OnlinePlay/Components/{RoomInfoPill.cs => PillContainer.cs} (72%) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs b/osu.Game/Screens/OnlinePlay/Components/PillContainer.cs similarity index 72% rename from osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs rename to osu.Game/Screens/OnlinePlay/Components/PillContainer.cs index 55de75cbcd..10a14d16da 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomInfoPill.cs +++ b/osu.Game/Screens/OnlinePlay/Components/PillContainer.cs @@ -5,21 +5,27 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Components { /// - /// Abstract class for "pill" components displayed as part of s. + /// Displays contents in a "pill". /// - public abstract class RoomInfoPill : OnlinePlayComposite + public class PillContainer : Container { private const float padding = 8; - protected Drawable Background { get; private set; } + public Drawable Background { get; private set; } - protected RoomInfoPill() + protected override Container Content { get; } = new Container + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + }; + + public PillContainer() { AutoSizeAxes = Axes.X; Height = 16; @@ -58,21 +64,12 @@ namespace osu.Game.Screens.OnlinePlay.Components }, Content = new[] { - new[] - { - CreateContent().With(d => - { - d.Anchor = Anchor.Centre; - d.Origin = Anchor.Centre; - }) - } + new[] { Content } } } } } }; } - - protected abstract Drawable CreateContent(); } } diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs index 7a4a638c2a..2d9e7c143c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs +++ b/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Specialized; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -11,10 +12,29 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A pill that displays the playlist item count. /// - public class PlaylistCountPill : RoomInfoPill + public class PlaylistCountPill : OnlinePlayComposite { private OsuTextFlowContainer count; + public PlaylistCountPill() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new PillContainer + { + Child = count = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12)) + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -28,12 +48,5 @@ namespace osu.Game.Screens.OnlinePlay.Components count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); count.AddText(" Maps"); } - - protected override Drawable CreateContent() => count = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12)) - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - }; } } diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs index 6d9e84d618..d18eb1bd94 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs @@ -16,14 +16,35 @@ namespace osu.Game.Screens.OnlinePlay.Components /// /// A pill that displays the room's current status. /// - public class RoomStatusPill : RoomInfoPill + public class RoomStatusPill : OnlinePlayComposite { [Resolved] private OsuColour colours { get; set; } private bool firstDisplay = true; + private PillContainer pill; private SpriteText statusText; + public RoomStatusPill() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = pill = new PillContainer + { + Child = statusText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), + Colour = Color4.Black + } + }; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -36,19 +57,11 @@ namespace osu.Game.Screens.OnlinePlay.Components { RoomStatus status = EndDate.Value < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); - Background.Alpha = 1; - Background.FadeColour(status.GetAppropriateColour(colours), firstDisplay ? 0 : 100); + pill.Background.Alpha = 1; + pill.Background.FadeColour(status.GetAppropriateColour(colours), firstDisplay ? 0 : 100); statusText.Text = status.Message; firstDisplay = false; } - - protected override Drawable CreateContent() => statusText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), - Colour = Color4.Black - }; } } From 4ac812de86da47906a1be2c6d267eefed697ef10 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 16:15:26 +0900 Subject: [PATCH 021/961] Add rank range pill --- .../Multiplayer/TestSceneRankRangePill.cs | 67 ++++++++++++++++ .../OnlinePlay/Components/RankRangePill.cs | 77 +++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs create mode 100644 osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs new file mode 100644 index 0000000000..d6bbaabfa6 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.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 NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneRankRangePill : MultiplayerTestScene + { + [SetUp] + public new void Setup() => Schedule(() => + { + Child = new RankRangePill + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }; + }); + + [Test] + public void TestSingleUser() + { + AddStep("add user", () => + { + Client.AddUser(new User + { + Id = 2, + Statistics = { GlobalRank = 1234 } + }); + + // Remove the local user so only the one above is displayed. + Client.RemoveUser(API.LocalUser.Value); + }); + } + + [Test] + public void TestMultipleUsers() + { + AddStep("add users", () => + { + Client.AddUser(new User + { + Id = 2, + Statistics = { GlobalRank = 1234 } + }); + + Client.AddUser(new User + { + Id = 3, + Statistics = { GlobalRank = 3333 } + }); + + Client.AddUser(new User + { + Id = 4, + Statistics = { GlobalRank = 4321 } + }); + + // Remove the local user so only the ones above are displayed. + Client.RemoveUser(API.LocalUser.Value); + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs b/osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs new file mode 100644 index 0000000000..d7bdf13f6a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs @@ -0,0 +1,77 @@ +// 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.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public class RankRangePill : MultiplayerRoomComposite + { + private OsuTextFlowContainer rankFlow; + + public RankRangePill() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new PillContainer + { + Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(4), + Children = new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(8), + Icon = FontAwesome.Solid.User + }, + rankFlow = new OsuTextFlowContainer(s => s.Font = OsuFont.GetFont(size: 12)) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + } + } + } + }; + } + + protected override void OnRoomUpdated() + { + base.OnRoomUpdated(); + + rankFlow.Clear(); + + if (Room == null || Room.Users.All(u => u.User == null)) + { + rankFlow.AddText("-"); + return; + } + + rankFlow.AddText("#"); + rankFlow.AddText(Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min().ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); + + rankFlow.AddText(" - "); + + rankFlow.AddText("#"); + rankFlow.AddText(Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max().ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); + } + } +} From aba09b20a5ffea00f513566ca35c7ec07fb6ee94 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 16:28:22 +0900 Subject: [PATCH 022/961] Add host under room title --- .../Multiplayer/TestSceneDrawableRoom.cs | 21 +++++--- .../Lounge/Components/DrawableRoom.cs | 52 +++++++++++++++++-- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 7fef5aba4d..3d65b5afda 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -8,6 +8,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Multiplayer @@ -27,27 +28,31 @@ namespace osu.Game.Tests.Visual.Multiplayer { createDrawableRoom(new Room { - Name = { Value = "Room name: Open - ending in 1 day" }, + Name = { Value = "Room 1" }, Status = { Value = new RoomStatusOpen() }, - EndDate = { Value = DateTimeOffset.Now.AddDays(1) } + EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { - Name = { Value = "Room name: Playing - ending in 1 day" }, + Name = { Value = "Room 2" }, Status = { Value = new RoomStatusPlaying() }, - EndDate = { Value = DateTimeOffset.Now.AddDays(1) } + EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { - Name = { Value = "Room name: Ended" }, + Name = { Value = "Room 3" }, Status = { Value = new RoomStatusEnded() }, - EndDate = { Value = DateTimeOffset.Now } + EndDate = { Value = DateTimeOffset.Now }, + Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { - Name = { Value = "Room name: Open" }, + Name = { Value = "Room 4" }, Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime } + Category = { Value = RoomCategory.Realtime }, + Host = { Value = new User { Username = "peppy", Id = 2 } } }), } }; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index b795b74e04..4c7847cef0 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -187,11 +187,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, } }, - new RoomName + new FillFlowContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Font = OsuFont.GetFont(size: 28) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new RoomNameText(), + new RoomHostText() + } }, new FillFlowContainer { @@ -262,11 +268,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected; - private class RoomName : OsuSpriteText + private class RoomNameText : OsuSpriteText { [Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))] private Bindable name { get; set; } + public RoomNameText() + { + Font = OsuFont.GetFont(size: 24); + } + [BackgroundDependencyLoader] private void load() { @@ -274,6 +285,41 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } + private class RoomHostText : OnlinePlayComposite + { + private LinkFlowContainer hostText; + + public RoomHostText() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + { + AutoSizeAxes = Axes.Both + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Host.BindValueChanged(host => + { + hostText.Clear(); + + if (host.NewValue != null) + { + hostText.AddText("hosted by "); + hostText.AddUserLink(host.NewValue); + } + }, true); + } + } + public MenuItem[] ContextMenuItems => new MenuItem[] { new OsuMenuItem("Create copy", MenuItemType.Standard, () => From c1fba3da6b49ed30abf2892fd63ab4eb2ff28fa7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 12 Jul 2021 16:30:34 +0900 Subject: [PATCH 023/961] Add solid background --- .../Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 4c7847cef0..a1f90f2d89 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -125,6 +125,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, new Container { Anchor = Anchor.CentreRight, From 8c4a257742060336bb022edd6f379aa938467f05 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Jul 2021 15:10:44 +0900 Subject: [PATCH 024/961] Add recent participants --- .../Multiplayer/TestSceneDrawableRoom.cs | 20 +- .../TestSceneRecentParticipantsList.cs | 93 +++++++ .../Components/RecentParticipantsList.cs | 238 ++++++++++++++++++ .../Lounge/Components/DrawableRoom.cs | 38 +++ 4 files changed, 381 insertions(+), 8 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs create mode 100644 osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 3d65b5afda..0970085c25 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.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.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -31,28 +32,24 @@ namespace osu.Game.Tests.Visual.Multiplayer Name = { Value = "Room 1" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, - Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { Name = { Value = "Room 2" }, Status = { Value = new RoomStatusPlaying() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, - Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { Name = { Value = "Room 3" }, Status = { Value = new RoomStatusEnded() }, EndDate = { Value = DateTimeOffset.Now }, - Host = { Value = new User { Username = "peppy", Id = 2 } } }), createDrawableRoom(new Room { Name = { Value = "Room 4" }, Status = { Value = new RoomStatusOpen() }, Category = { Value = RoomCategory.Realtime }, - Host = { Value = new User { Username = "peppy", Id = 2 } } }), } }; @@ -60,11 +57,18 @@ namespace osu.Game.Tests.Visual.Multiplayer private DrawableRoom createDrawableRoom(Room room) { - var drawableRoom = new DrawableRoom(room) - { - MatchingFilter = true - }; + room.Host.Value ??= new User { Username = "peppy", Id = 2 }; + if (room.RecentParticipants.Count == 0) + { + room.RecentParticipants.AddRange(Enumerable.Range(0, 20).Select(i => new User + { + Id = i, + Username = $"User {i}" + })); + } + + var drawableRoom = new DrawableRoom(room) { MatchingFilter = true }; drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected; return drawableRoom; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs new file mode 100644 index 0000000000..ca8dc74759 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -0,0 +1,93 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Tests.Visual.OnlinePlay; +using osu.Game.Users; +using osu.Game.Users.Drawables; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneRecentParticipantsList : OnlinePlayTestScene + { + private RecentParticipantsList list; + + [SetUp] + public new void Setup() => Schedule(() => + { + SelectedRoom.Value = new Room { Name = { Value = "test room" } }; + + Child = list = new RecentParticipantsList + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + NumberOfAvatars = 3 + }; + }); + + [Test] + public void TestAvatarCount() + { + AddStep("add 50 users", () => + { + for (int i = 0; i < 50; i++) + { + SelectedRoom.Value.RecentParticipants.Add(new User + { + Id = i, + Username = $"User {i}" + }); + } + }); + + AddStep("set 3 avatars", () => list.NumberOfAvatars = 3); + AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("47 hidden users", () => list.ChildrenOfType().Single().Count == 47); + + AddStep("set 10 avatars", () => list.NumberOfAvatars = 10); + AddAssert("10 avatars displayed", () => list.ChildrenOfType().Count() == 10); + AddAssert("40 hidden users", () => list.ChildrenOfType().Single().Count == 40); + } + + [Test] + public void TestAddAndRemoveUsers() + { + AddStep("add 50 users", () => + { + for (int i = 0; i < 50; i++) + { + SelectedRoom.Value.RecentParticipants.Add(new User + { + Id = i, + Username = $"User {i}" + }); + } + }); + + AddStep("remove from start", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0)); + AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("46 hidden users", () => list.ChildrenOfType().Single().Count == 46); + + AddStep("remove from end", () => SelectedRoom.Value.RecentParticipants.RemoveAt(SelectedRoom.Value.RecentParticipants.Count - 1)); + AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("45 hidden users", () => list.ChildrenOfType().Single().Count == 45); + + AddRepeatStep("remove 45 users", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0), 45); + AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); + AddAssert("hidden users bubble hidden", () => list.ChildrenOfType().Single().Alpha < 0.5f); + + AddStep("remove another user", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0)); + AddAssert("2 avatars displayed", () => list.ChildrenOfType().Count() == 2); + AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); + + AddRepeatStep("remove the remaining two users", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0), 2); + AddAssert("0 avatars displayed", () => !list.ChildrenOfType().Any()); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs new file mode 100644 index 0000000000..d73387342a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs @@ -0,0 +1,238 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Specialized; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics.Sprites; +using osu.Game.Users; +using osu.Game.Users.Drawables; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public class RecentParticipantsList : OnlinePlayComposite + { + private const float avatar_size = 36; + + private FillFlowContainer avatarFlow; + private HiddenUserCount hiddenUsers; + + public RecentParticipantsList() + { + AutoSizeAxes = Axes.X; + Height = 60; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + MaskingSmoothness = 2, + CornerRadius = 10, + Shear = new Vector2(0.2f, 0), + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#2E3835") + } + }, + new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), + Padding = new MarginPadding { Left = 8, Right = 16 }, + Children = new Drawable[] + { + new SpriteIcon + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(16), + Icon = FontAwesome.Solid.User, + }, + avatarFlow = new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4) + }, + hiddenUsers = new HiddenUserCount + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + } + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + RecentParticipants.BindCollectionChanged(onParticipantsChanged, true); + } + + private int numberOfAvatars = 3; + + public int NumberOfAvatars + { + get => numberOfAvatars; + set + { + numberOfAvatars = value; + + if (LoadState < LoadState.Loaded) + return; + + // Reinitialising the list looks janky, but this is unlikely to be used in a setting where it's visible. + clearUsers(); + foreach (var u in RecentParticipants) + addUser(u); + } + } + + private void onParticipantsChanged(object sender, NotifyCollectionChangedEventArgs e) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + foreach (var added in e.NewItems.OfType()) + addUser(added); + break; + + case NotifyCollectionChangedAction.Remove: + foreach (var removed in e.OldItems.OfType()) + removeUser(removed); + break; + + case NotifyCollectionChangedAction.Reset: + clearUsers(); + break; + + case NotifyCollectionChangedAction.Replace: + case NotifyCollectionChangedAction.Move: + // Easiest is to just reinitialise the whole list. These are unlikely to ever be use cases. + clearUsers(); + foreach (var u in RecentParticipants) + addUser(u); + break; + } + } + + private void addUser(User user) + { + if (avatarFlow.Count < NumberOfAvatars) + avatarFlow.Add(new CircularAvatar { User = user }); + else + hiddenUsers.Count++; + } + + private void removeUser(User user) + { + if (avatarFlow.RemoveAll(a => a.User == user) > 0) + { + if (RecentParticipants.Count >= NumberOfAvatars) + { + avatarFlow.Add(new CircularAvatar { User = RecentParticipants.First(u => avatarFlow.All(a => a.User != u)) }); + hiddenUsers.Count--; + } + } + else + hiddenUsers.Count--; + } + + private void clearUsers() + { + avatarFlow.Clear(); + hiddenUsers.Count = 0; + } + + private class CircularAvatar : CompositeDrawable + { + public User User + { + get => avatar.User; + set => avatar.User = value; + } + + private readonly UpdateableAvatar avatar; + + public CircularAvatar() + { + Size = new Vector2(avatar_size); + + InternalChild = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = avatar = new UpdateableAvatar(showUsernameTooltip: true) { RelativeSizeAxes = Axes.Both } + }; + } + } + + public class HiddenUserCount : CompositeDrawable + { + public int Count + { + get => count; + set + { + count = value; + countText.Text = $"+{count}"; + + if (count > 0) + Show(); + else + Hide(); + } + } + + private int count; + + private readonly SpriteText countText; + + public HiddenUserCount() + { + Size = new Vector2(avatar_size); + Alpha = 0; + + InternalChild = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + countText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + }; + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index a1f90f2d89..9385c3cae8 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -91,6 +91,22 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } + private int numberOfAvatars = 3; + + public int NumberOfAvatars + { + get => numberOfAvatars; + set + { + numberOfAvatars = value; + + if (recentParticipantsList != null) + recentParticipantsList.NumberOfAvatars = value; + } + } + + private RecentParticipantsList recentParticipantsList; + public bool FilteringActive { get; set; } public DrawableRoom(Room room) @@ -228,6 +244,28 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } }, + new FillFlowContainer + { + Name = "Right content", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Right = 10, + Vertical = 5 + }, + Children = new Drawable[] + { + recentParticipantsList = new RecentParticipantsList + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + NumberOfAvatars = NumberOfAvatars + } + } + } }, }, }, From 689cee832c6f8ea2574d8bac1debd817d4e44cf9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Jul 2021 15:50:46 +0900 Subject: [PATCH 025/961] Fix 1px gaps in DrawableRoom background --- .../Lounge/Components/DrawableRoom.cs | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 9385c3cae8..f7f846ecfb 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -141,41 +141,49 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { - new Box + // This resolves 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. + new BufferedContainer { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), - }, - new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + Children = new Drawable[] { - new Dimension(GridSizeMode.Relative, 0.2f) - }, - Content = new[] - { - new Drawable[] + new Box { - new Box + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), + new Dimension(GridSizeMode.Relative, 0.2f) }, - new Box + Content = new[] { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) - }, - } + new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + }, + } + } + }, } }, new Container From ab282b9e59ca187954ca18ba0082ffa9e4e5b8c1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Jul 2021 16:00:42 +0900 Subject: [PATCH 026/961] Remove RoomInspector from the lounge --- .../Multiplayer/TestSceneLoungeRoomInfo.cs | 49 ---------- .../Lounge/Components/ParticipantInfo.cs | 88 ------------------ .../OnlinePlay/Lounge/Components/RoomInfo.cs | 86 ------------------ .../Lounge/Components/RoomInspector.cs | 91 ------------------- .../Lounge/Components/RoomsContainer.cs | 2 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 33 +++---- 6 files changed, 12 insertions(+), 337 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs deleted file mode 100644 index 471d0b6c98..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs +++ /dev/null @@ -1,49 +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 NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Online.Rooms; -using osu.Game.Online.Rooms.RoomStatuses; -using osu.Game.Screens.OnlinePlay.Lounge.Components; -using osu.Game.Tests.Visual.OnlinePlay; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneLoungeRoomInfo : OnlinePlayTestScene - { - [SetUp] - public new void Setup() => Schedule(() => - { - SelectedRoom.Value = new Room(); - - Child = new RoomInfo - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 500 - }; - }); - - [Test] - public void TestNonSelectedRoom() - { - AddStep("set null room", () => SelectedRoom.Value.RoomID.Value = null); - } - - [Test] - public void TestOpenRoom() - { - AddStep("set open room", () => - { - SelectedRoom.Value.RoomID.Value = 0; - SelectedRoom.Value.Name.Value = "Room 0"; - SelectedRoom.Value.Host.Value = new User { Username = "peppy", Id = 2 }; - SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMonths(1); - SelectedRoom.Value.Status.Value = new RoomStatusOpen(); - }); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs deleted file mode 100644 index bc4506b78e..0000000000 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/ParticipantInfo.cs +++ /dev/null @@ -1,88 +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 Humanizer; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Users.Drawables; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Lounge.Components -{ - public class ParticipantInfo : OnlinePlayComposite - { - public ParticipantInfo() - { - RelativeSizeAxes = Axes.X; - Height = 15f; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - OsuSpriteText summary; - Container flagContainer; - LinkFlowContainer hostText; - - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5f, 0f), - Children = new Drawable[] - { - flagContainer = new Container - { - Width = 22f, - RelativeSizeAxes = Axes.Y, - }, - hostText = new LinkFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both - } - }, - }, - new FillFlowContainer - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Colour = colours.Gray9, - Children = new[] - { - summary = new OsuSpriteText - { - Text = "0 participants", - } - }, - }, - }; - - Host.BindValueChanged(host => - { - hostText.Clear(); - flagContainer.Clear(); - - if (host.NewValue != null) - { - hostText.AddText("hosted by "); - hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(Typeface.Torus, weight: FontWeight.Bold, italics: true)); - - flagContainer.Child = new UpdateableFlag(host.NewValue.Country) { RelativeSizeAxes = Axes.Both }; - } - }, true); - - ParticipantCount.BindValueChanged(count => summary.Text = "participant".ToQuantity(count.NewValue), true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs deleted file mode 100644 index 819e19ad1e..0000000000 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInfo.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Screens.OnlinePlay.Components; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Lounge.Components -{ - public class RoomInfo : OnlinePlayComposite - { - private readonly List statusElements = new List(); - private readonly OsuTextFlowContainer roomName; - - public RoomInfo() - { - AutoSizeAxes = Axes.Y; - - RoomLocalUserInfo localUserInfo; - EndDateInfo statusInfo; - ModeTypeInfo typeInfo; - ParticipantInfo participantInfo; - - InternalChild = new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - Spacing = new Vector2(0, 10), - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - roomName = new OsuTextFlowContainer(t => t.Font = OsuFont.GetFont(size: 30)) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - participantInfo = new ParticipantInfo(), - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - statusInfo = new EndDateInfo(), - typeInfo = new ModeTypeInfo - { - Anchor = Anchor.BottomRight, - Origin = Anchor.BottomRight - } - } - }, - localUserInfo = new RoomLocalUserInfo(), - } - }; - - statusElements.AddRange(new Drawable[] - { - statusInfo, typeInfo, participantInfo, localUserInfo - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - if (RoomID.Value == null) - statusElements.ForEach(e => e.FadeOut()); - RoomID.BindValueChanged(id => - { - if (id.NewValue == null) - statusElements.ForEach(e => e.FadeOut(100)); - else - statusElements.ForEach(e => e.FadeIn(100)); - }, true); - RoomName.BindValueChanged(name => - { - roomName.Text = name.NewValue ?? "No room selected"; - }, true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs deleted file mode 100644 index c28354c753..0000000000 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomInspector.cs +++ /dev/null @@ -1,91 +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.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Screens.OnlinePlay.Components; -using osuTK.Graphics; - -namespace osu.Game.Screens.OnlinePlay.Lounge.Components -{ - public class RoomInspector : OnlinePlayComposite - { - private const float transition_duration = 100; - - private readonly MarginPadding contentPadding = new MarginPadding { Horizontal = 20, Vertical = 10 }; - - [Resolved] - private BeatmapManager beatmaps { get; set; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - OverlinedHeader participantsHeader; - - InternalChildren = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.25f - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 30 }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new RoomInfo - { - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding { Vertical = 60 }, - }, - participantsHeader = new OverlinedHeader("Recent Participants"), - new ParticipantsDisplay(Direction.Vertical) - { - RelativeSizeAxes = Axes.X, - Height = ParticipantsList.TILE_SIZE * 3, - Details = { BindTarget = participantsHeader.Details } - } - } - } - }, - new Drawable[] { new OverlinedPlaylistHeader(), }, - new Drawable[] - { - new DrawableRoomPlaylist(false, false) - { - RelativeSizeAxes = Axes.Both, - Items = { BindTarget = Playlist } - }, - }, - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - } - } - } - }; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 5f135a3e90..0c6c84e656 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -60,7 +60,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Spacing = new Vector2(2), + Spacing = new Vector2(10), } }; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index f24577a8a5..9004fe8dcc 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -57,31 +57,20 @@ namespace osu.Game.Screens.OnlinePlay.Lounge content = new Container { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Child = new Container { - new Container + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Width = 0.55f, - Children = new Drawable[] + scrollContainer = new OsuScrollContainer { - scrollContainer = new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - ScrollbarOverlapsContent = false, - Padding = new MarginPadding(10), - Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } - }, - loadingLayer = new LoadingLayer(true), - } - }, - new RoomInspector - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.Both, - Width = 0.45f, - }, + RelativeSizeAxes = Axes.Both, + ScrollbarOverlapsContent = false, + Padding = new MarginPadding(10), + Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } + }, + loadingLayer = new LoadingLayer(true), + } }, }, filter = CreateFilterControl().With(d => From 0cb80e105b22c3f4dc8ba7ba24a78d4c10a01b77 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Jul 2021 16:02:18 +0900 Subject: [PATCH 027/961] Renamespace classes --- osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs | 2 +- .../Visual/Multiplayer/TestSceneRecentParticipantsList.cs | 2 +- .../Screens/OnlinePlay/{ => Lounge}/Components/EndDateInfo.cs | 2 +- .../Screens/OnlinePlay/{ => Lounge}/Components/PillContainer.cs | 2 +- .../OnlinePlay/{ => Lounge}/Components/PlaylistCountPill.cs | 2 +- .../Screens/OnlinePlay/{ => Lounge}/Components/RankRangePill.cs | 2 +- .../{ => Lounge}/Components/RecentParticipantsList.cs | 2 +- .../OnlinePlay/{ => Lounge}/Components/RoomStatusPill.cs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/EndDateInfo.cs (97%) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/PillContainer.cs (97%) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/PlaylistCountPill.cs (96%) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/RankRangePill.cs (97%) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/RecentParticipantsList.cs (99%) rename osu.Game/Screens/OnlinePlay/{ => Lounge}/Components/RoomStatusPill.cs (97%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs index d6bbaabfa6..5e28b3f8e5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs @@ -3,7 +3,7 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index ca8dc74759..c9959b3467 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -6,7 +6,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Users; using osu.Game.Users.Drawables; diff --git a/osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs index 3f93279461..3207d373db 100644 --- a/osu.Game/Screens/OnlinePlay/Components/EndDateInfo.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/EndDateInfo.cs @@ -7,7 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Graphics; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class EndDateInfo : OnlinePlayComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/PillContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Components/PillContainer.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs index 10a14d16da..15a532eaf3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/PillContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { /// /// Displays contents in a "pill". diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs similarity index 96% rename from osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs index 2d9e7c143c..8d8309fcaa 100644 --- a/osu.Game/Screens/OnlinePlay/Components/PlaylistCountPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs @@ -7,7 +7,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { /// /// A pill that displays the playlist item count. diff --git a/osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs index d7bdf13f6a..8f685ba033 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RankRangePill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs @@ -11,7 +11,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Screens.OnlinePlay.Multiplayer; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RankRangePill : MultiplayerRoomComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs similarity index 99% rename from osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index d73387342a..bbea1ea1c3 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -15,7 +15,7 @@ using osu.Game.Users.Drawables; using osuTK; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RecentParticipantsList : OnlinePlayComposite { diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs rename to osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs index d18eb1bd94..ae17a80705 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs @@ -11,7 +11,7 @@ using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osuTK.Graphics; -namespace osu.Game.Screens.OnlinePlay.Components +namespace osu.Game.Screens.OnlinePlay.Lounge.Components { /// /// A pill that displays the room's current status. From b5d4b9444fbffcf2b2e202145a405d2559c7a5c7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 13 Jul 2021 16:51:29 +0900 Subject: [PATCH 028/961] wip --- .../Lounge/Components/FilterControl.cs | 70 ++++++++----------- .../Components/PlaylistsFilterControl.cs | 10 ++- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs index 7fc1c670ca..1827efb4a2 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs @@ -5,19 +5,21 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; -using osuTK.Graphics; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public abstract class FilterControl : CompositeDrawable { protected const float VERTICAL_PADDING = 10; - protected const float HORIZONTAL_PADDING = 80; + protected const float HORIZONTAL_PADDING = 20; + + protected readonly FillFlowContainer Filters; [Resolved(CanBeNull = true)] private Bindable filter { get; set; } @@ -25,60 +27,50 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [Resolved] private IBindable ruleset { get; set; } - private readonly Box tabStrip; private readonly SearchTextBox search; - private readonly PageTabControl tabs; + private readonly Dropdown statusDropdown; protected FilterControl() { - InternalChildren = new Drawable[] + InternalChild = new Container { - new Box + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.25f, + Top = VERTICAL_PADDING, + Horizontal = HORIZONTAL_PADDING }, - tabStrip = new Box + Children = new Drawable[] { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - Height = 1, - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding + search = new FilterSearchTextBox { - Top = VERTICAL_PADDING, - Horizontal = HORIZONTAL_PADDING + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.X, + Width = 0.6f, }, - Children = new Drawable[] + Filters = new FillFlowContainer { - search = new FilterSearchTextBox + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + Padding = new MarginPadding { Vertical = 30 }, + Child = statusDropdown = new SlimEnumDropdown { - RelativeSizeAxes = Axes.X, - }, - tabs = new PageTabControl - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - }, - } + Anchor = Anchor.BottomRight, + Origin = Anchor.TopRight, + RelativeSizeAxes = Axes.None, + Width = 160, + } + }, } }; - - tabs.Current.Value = RoomStatusFilter.Open; - tabs.Current.TriggerChange(); } [BackgroundDependencyLoader] private void load(OsuColour colours) { filter ??= new Bindable(); - tabStrip.Colour = colours.Yellow; } protected override void LoadComplete() @@ -87,7 +79,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components search.Current.BindValueChanged(_ => updateFilterDebounced()); ruleset.BindValueChanged(_ => UpdateFilter()); - tabs.Current.BindValueChanged(_ => UpdateFilter(), true); + statusDropdown.Current.BindValueChanged(_ => UpdateFilter(), true); } private ScheduledDelegate scheduledFilterUpdate; @@ -106,7 +98,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components var criteria = CreateCriteria(); criteria.SearchString = search.Current.Value; - criteria.Status = tabs.Current.Value; + criteria.Status = statusDropdown.Current.Value; criteria.Ruleset = ruleset.Value; filter.Value = criteria; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs index a463742097..e6309a8e06 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs @@ -9,18 +9,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class PlaylistsFilterControl : FilterControl { - private readonly Dropdown dropdown; + private readonly Dropdown categoryDropdown; public PlaylistsFilterControl() { - AddInternal(dropdown = new SlimEnumDropdown + Filters.Add(categoryDropdown = new SlimEnumDropdown { Anchor = Anchor.BottomRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.None, Width = 160, - X = -HORIZONTAL_PADDING, - Y = -30 }); } @@ -28,14 +26,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { base.LoadComplete(); - dropdown.Current.BindValueChanged(_ => UpdateFilter()); + categoryDropdown.Current.BindValueChanged(_ => UpdateFilter()); } protected override FilterCriteria CreateCriteria() { var criteria = base.CreateCriteria(); - switch (dropdown.Current.Value) + switch (categoryDropdown.Current.Value) { case PlaylistsCategory.Normal: criteria.Category = "normal"; From 0e89bafd178f5d180357ec0ae8102f8462e226b2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 16:48:53 +0900 Subject: [PATCH 029/961] Add special category pill + secondary background --- .../Multiplayer/TestSceneDrawableRoom.cs | 8 +- .../Lounge/Components/DrawableRoom.cs | 266 ++++++++++-------- .../Lounge/Components/PillContainer.cs | 7 +- .../Components/RoomSpecialCategoryPill.cs | 49 ++++ .../Screens/OnlinePlay/OnlinePlayComposite.cs | 3 + 5 files changed, 209 insertions(+), 124 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 0970085c25..ee84a6b6cc 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -47,10 +47,16 @@ namespace osu.Game.Tests.Visual.Multiplayer }), createDrawableRoom(new Room { - Name = { Value = "Room 4" }, + Name = { Value = "Room 4 (realtime)" }, Status = { Value = new RoomStatusOpen() }, Category = { Value = RoomCategory.Realtime }, }), + createDrawableRoom(new Room + { + Name = { Value = "Room 4 (spotlight)" }, + Status = { Value = new RoomStatusOpen() }, + Category = { Value = RoomCategory.Spotlight }, + }), } }; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index f7f846ecfb..d36f0275df 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -105,7 +105,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } + private readonly Bindable roomCategory = new Bindable(); + private RecentParticipantsList recentParticipantsList; + private RoomSpecialCategoryPill specialCategoryPill; + private Drawable spotlightGlow; public bool FilteringActive { get; set; } @@ -126,156 +130,169 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { new Container { - Name = @"Room content", RelativeSizeAxes = Axes.Both, - Child = new Container + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = corner_radius, - EdgeEffect = new EdgeEffectParameters + new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(40), - Radius = 5, + RelativeSizeAxes = Axes.Both }, - Children = new Drawable[] + new Container { - // This resolves 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. - new BufferedContainer + Name = @"Room content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, + Child = new Container { RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius, Children = new Drawable[] { - new Box + // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. + new BufferedContainer { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) + { + RelativeSizeAxes = Axes.Both + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, 0.2f) + }, + Content = new[] + { + new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + }, + } + } + }, + spotlightGlow = new Box + { + RelativeSizeAxes = Axes.Y, + Width = 50, + Colour = ColourInfo.GradientHorizontal(colours.Pink.Opacity(0.5f), colours.Pink.Opacity(0)) + } + }, }, new Container { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, + Name = @"Left details", RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - Child = new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both } - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + Padding = new MarginPadding { - new Dimension(GridSizeMode.Relative, 0.2f) + Left = 20, + Vertical = 5 }, - Content = new[] + Children = new Drawable[] { - new Drawable[] + new FillFlowContainer { - new Box + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) - }, - } - } - }, - } - }, - new Container - { - Name = @"Left details", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Left = 20, - Vertical = 5 - }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new RoomStatusPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft + new RoomStatusPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + specialCategoryPill = new RoomSpecialCategoryPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new EndDateInfo + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + } }, - new EndDateInfo - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - } - }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new RoomNameText(), - new RoomHostText() - } - }, - new FillFlowContainer - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new PlaylistCountPill + new FillFlowContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new RoomNameText(), + new RoomHostText() + } }, - new StarRatingRangeDisplay + new FillFlowContainer { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Scale = new Vector2(0.85f) + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), + Children = new Drawable[] + { + new PlaylistCountPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new StarRatingRangeDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Scale = new Vector2(0.85f) + } + } } } - } - } - }, - new FillFlowContainer - { - Name = "Right content", - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Padding = new MarginPadding - { - Right = 10, - Vertical = 5 - }, - Children = new Drawable[] - { - recentParticipantsList = new RecentParticipantsList + }, + new FillFlowContainer { + Name = "Right content", Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - NumberOfAvatars = NumberOfAvatars + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Right = 10, + Vertical = 5 + }, + Children = new Drawable[] + { + recentParticipantsList = new RecentParticipantsList + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + NumberOfAvatars = NumberOfAvatars + } + } } - } - } + }, + }, }, - }, + } }, new StatusColouredContainer(transition_duration) { @@ -315,6 +332,21 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components this.FadeInFromZero(transition_duration); else Alpha = 0; + + roomCategory.BindTo(Room.Category); + roomCategory.BindValueChanged(c => + { + if (c.NewValue == RoomCategory.Spotlight) + { + specialCategoryPill.Show(); + spotlightGlow.Show(); + } + else + { + specialCategoryPill.Hide(); + spotlightGlow.Hide(); + } + }, true); } protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs index 15a532eaf3..ca153f7e9a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -16,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { private const float padding = 8; - public Drawable Background { get; private set; } + public readonly Drawable Background; protected override Container Content { get; } = new Container { @@ -29,11 +28,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { AutoSizeAxes = Axes.X; Height = 16; - } - [BackgroundDependencyLoader] - private void load() - { InternalChild = new CircularContainer { Anchor = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs new file mode 100644 index 0000000000..6cdbeb2af4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomSpecialCategoryPill.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Lounge.Components +{ + public class RoomSpecialCategoryPill : OnlinePlayComposite + { + private SpriteText text; + + public RoomSpecialCategoryPill() + { + AutoSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + InternalChild = new PillContainer + { + Background = + { + Colour = colours.Pink, + Alpha = 1 + }, + Child = text = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(weight: FontWeight.SemiBold, size: 12), + Colour = Color4.Black + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Category.BindValueChanged(c => text.Text = c.NewValue.ToString(), true); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs index eb0b23f13f..ffaeb8fc97 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayComposite.cs @@ -35,6 +35,9 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room))] protected BindableList Playlist { get; private set; } + [Resolved(typeof(Room))] + protected Bindable Category { get; private set; } + [Resolved(typeof(Room))] protected BindableList RecentParticipants { get; private set; } From e0c61c24b1529654bf9a891384b8ed3660d84940 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 16:51:20 +0900 Subject: [PATCH 030/961] Remove spotlights glow --- .../Lounge/Components/DrawableRoom.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index d36f0275df..63dffe432b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -11,7 +11,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; -using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; @@ -109,7 +108,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private RecentParticipantsList recentParticipantsList; private RoomSpecialCategoryPill specialCategoryPill; - private Drawable spotlightGlow; public bool FilteringActive { get; set; } @@ -153,7 +151,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new BufferedContainer { RelativeSizeAxes = Axes.Both, - Children = new[] + Children = new Drawable[] { new Box { @@ -188,12 +186,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } }, - spotlightGlow = new Box - { - RelativeSizeAxes = Axes.Y, - Width = 50, - Colour = ColourInfo.GradientHorizontal(colours.Pink.Opacity(0.5f), colours.Pink.Opacity(0)) - } }, }, new Container @@ -336,16 +328,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomCategory.BindTo(Room.Category); roomCategory.BindValueChanged(c => { + // Todo: Tournament category... if (c.NewValue == RoomCategory.Spotlight) - { specialCategoryPill.Show(); - spotlightGlow.Show(); - } else - { specialCategoryPill.Hide(); - spotlightGlow.Hide(); - } }, true); } From da3b40a4ddd8081e4d626dac0f44d2ce417e5548 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 16:56:39 +0900 Subject: [PATCH 031/961] Add default background to panel, reduce nesting --- .../Lounge/Components/DrawableRoom.cs | 248 +++++++++--------- 1 file changed, 127 insertions(+), 121 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 63dffe432b..1e8ea86eb7 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -126,165 +126,171 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Children = new Drawable[] { - new Container + // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. + new BufferedContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) { RelativeSizeAxes = Axes.Both }, - new Container + } + }, + new Container + { + Name = @"Room content", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = corner_radius, + Children = new Drawable[] { - Name = @"Room content", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, - Child = new Container + // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. + new BufferedContainer { RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = corner_radius, Children = new Drawable[] { - // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. - new BufferedContainer + new Box { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), - }, - new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) - { - RelativeSizeAxes = Axes.Both - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, 0.2f) - }, - Content = new[] - { - new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) - }, - } - } - }, - }, + Colour = Color4Extensions.FromHex(@"#27302E"), }, - new Container + new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) + { + RelativeSizeAxes = Axes.Both + }, + new GridContainer { - Name = @"Left details", RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding + ColumnDimensions = new[] { - Left = 20, - Vertical = 5 + new Dimension(GridSizeMode.Relative, 0.2f) }, + Content = new[] + { + new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"#27302E"), + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + }, + } + } + }, + }, + }, + new Container + { + Name = @"Left details", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Left = 20, + Vertical = 5 + }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), Children = new Drawable[] { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new RoomStatusPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - specialCategoryPill = new RoomSpecialCategoryPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - new EndDateInfo - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - } - }, - new FillFlowContainer + new RoomStatusPill { Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new RoomNameText(), - new RoomHostText() - } + Origin = Anchor.CentreLeft }, - new FillFlowContainer + specialCategoryPill = new RoomSpecialCategoryPill { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), - Children = new Drawable[] - { - new PlaylistCountPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new StarRatingRangeDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Scale = new Vector2(0.85f) - } - } - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new EndDateInfo + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, } }, new FillFlowContainer { - Name = "Right content", - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Padding = new MarginPadding - { - Right = 10, - Vertical = 5 - }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, Children = new Drawable[] { - recentParticipantsList = new RecentParticipantsList + new RoomNameText(), + new RoomHostText() + } + }, + new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(4), + Children = new Drawable[] + { + new PlaylistCountPill { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - NumberOfAvatars = NumberOfAvatars + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new StarRatingRangeDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Scale = new Vector2(0.85f) } } } - }, + } }, + new FillFlowContainer + { + Name = "Right content", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Right = 10, + Vertical = 5 + }, + Children = new Drawable[] + { + recentParticipantsList = new RecentParticipantsList + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + NumberOfAvatars = NumberOfAvatars + } + } + } }, - } + }, }, new StatusColouredContainer(transition_duration) { From f6b81b76e88cc4c6b4307719150ba42cc93fbecc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 17:46:32 +0900 Subject: [PATCH 032/961] Add shadow --- .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 1e8ea86eb7..441b33abf0 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; @@ -117,8 +118,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.X; Height = height; - CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2; + Masking = true; + CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(40), + Radius = 5, + }; } [BackgroundDependencyLoader] From 0bfaf11d515b45c12ca6c1196ffd2a46bca71b4a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 17:46:45 +0900 Subject: [PATCH 033/961] Remove/fix paddings in lounge --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 9004fe8dcc..4930c432d8 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -52,32 +52,49 @@ namespace osu.Game.Screens.OnlinePlay.Lounge RoomsContainer roomsContainer; OsuScrollContainer scrollContainer; - InternalChildren = new Drawable[] + InternalChild = content = new Container { - content = new Container + RelativeSizeAxes = Axes.Both, + Child = new GridContainer { RelativeSizeAxes = Axes.Both, - Child = new Container + RowDimensions = new[] { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 10) + }, + Content = new[] + { + new Drawable[] { - scrollContainer = new OsuScrollContainer + filter = CreateFilterControl().With(d => + { + d.RelativeSizeAxes = Axes.X; + d.Height = 80; + d.Depth = -1; + }), + }, + null, + new Drawable[] + { + new Container { RelativeSizeAxes = Axes.Both, - ScrollbarOverlapsContent = false, - Padding = new MarginPadding(10), - Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } + Children = new Drawable[] + { + scrollContainer = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + ScrollbarOverlapsContent = false, + Padding = new MarginPadding(10), + Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } + }, + loadingLayer = new LoadingLayer(true), + } }, - loadingLayer = new LoadingLayer(true), } - }, + } }, - filter = CreateFilterControl().With(d => - { - d.RelativeSizeAxes = Axes.X; - d.Height = 80; - }) }; // scroll selected room into view on selection. @@ -109,9 +126,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge content.Padding = new MarginPadding { - Top = filter.DrawHeight, - Left = WaveOverlayContainer.WIDTH_PADDING - DrawableRoom.SELECTION_BORDER_WIDTH + HORIZONTAL_OVERFLOW_PADDING, - Right = WaveOverlayContainer.WIDTH_PADDING + HORIZONTAL_OVERFLOW_PADDING, + Left = WaveOverlayContainer.WIDTH_PADDING, + Right = WaveOverlayContainer.WIDTH_PADDING, }; } From c64230315f083a9b4e5c9c2bfaca668846d4991c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 18:10:59 +0900 Subject: [PATCH 034/961] Adjust layouts --- .../Lounge/Components/FilterControl.cs | 18 +++++-------- .../Components/PlaylistsFilterControl.cs | 2 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 27 ++++++------------- 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs index 1827efb4a2..36fba68a0c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs @@ -16,9 +16,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public abstract class FilterControl : CompositeDrawable { - protected const float VERTICAL_PADDING = 10; - protected const float HORIZONTAL_PADDING = 20; - protected readonly FillFlowContainer Filters; [Resolved(CanBeNull = true)] @@ -32,14 +29,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected FilterControl() { - InternalChild = new Container + RelativeSizeAxes = Axes.X; + Height = 70; + + InternalChild = new FillFlowContainer { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Top = VERTICAL_PADDING, - Horizontal = HORIZONTAL_PADDING - }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(10), Children = new Drawable[] { search = new FilterSearchTextBox @@ -54,10 +51,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10), - Padding = new MarginPadding { Vertical = 30 }, Child = statusDropdown = new SlimEnumDropdown { - Anchor = Anchor.BottomRight, + Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.None, Width = 160, diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs index e6309a8e06..bbf34d3893 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Filters.Add(categoryDropdown = new SlimEnumDropdown { - Anchor = Anchor.BottomRight, + Anchor = Anchor.TopRight, Origin = Anchor.TopRight, RelativeSizeAxes = Axes.None, Width = 160, diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 4930c432d8..492473e550 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -55,24 +55,25 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChild = content = new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Top = 20, + Left = WaveOverlayContainer.WIDTH_PADDING, + Right = WaveOverlayContainer.WIDTH_PADDING, + }, Child = new GridContainer { RelativeSizeAxes = Axes.Both, RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, 10) + new Dimension(GridSizeMode.Absolute, 20) }, Content = new[] { new Drawable[] { - filter = CreateFilterControl().With(d => - { - d.RelativeSizeAxes = Axes.X; - d.Height = 80; - d.Depth = -1; - }), + filter = CreateFilterControl().With(d => d.Depth = -1), }, null, new Drawable[] @@ -86,7 +87,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { RelativeSizeAxes = Axes.Both, ScrollbarOverlapsContent = false, - Padding = new MarginPadding(10), Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } }, loadingLayer = new LoadingLayer(true), @@ -120,17 +120,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge } } - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - content.Padding = new MarginPadding - { - Left = WaveOverlayContainer.WIDTH_PADDING, - Right = WaveOverlayContainer.WIDTH_PADDING, - }; - } - protected override void OnFocus(FocusEvent e) { filter.TakeFocus(); From 3e6b9bd48d595d3753c5f52c35f23802eb7bfbf1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 18:24:30 +0900 Subject: [PATCH 035/961] Add filter background --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 70 +++++++++++-------- 1 file changed, 41 insertions(+), 29 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 492473e550..068bc34a6c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; using osu.Framework.Screens; using osu.Game.Graphics.Containers; @@ -17,6 +18,7 @@ using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge { @@ -52,49 +54,59 @@ namespace osu.Game.Screens.OnlinePlay.Lounge RoomsContainer roomsContainer; OsuScrollContainer scrollContainer; - InternalChild = content = new Container + InternalChildren = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding + new Box { - Top = 20, - Left = WaveOverlayContainer.WIDTH_PADDING, - Right = WaveOverlayContainer.WIDTH_PADDING, + RelativeSizeAxes = Axes.X, + Height = 100, + Colour = Color4.Black, + Alpha = 0.5f, }, - Child = new GridContainer + content = new Container { RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + Padding = new MarginPadding { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, 20) + Top = 20, + Left = WaveOverlayContainer.WIDTH_PADDING, + Right = WaveOverlayContainer.WIDTH_PADDING, }, - Content = new[] + Child = new GridContainer { - new Drawable[] + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - filter = CreateFilterControl().With(d => d.Depth = -1), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 20) }, - null, - new Drawable[] + Content = new[] { - new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - scrollContainer = new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - ScrollbarOverlapsContent = false, - Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } - }, - loadingLayer = new LoadingLayer(true), - } + filter = CreateFilterControl().With(d => d.Depth = -1), }, + null, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + scrollContainer = new OsuScrollContainer + { + RelativeSizeAxes = Axes.Both, + ScrollbarOverlapsContent = false, + Child = roomsContainer = new RoomsContainer { JoinRequested = joinRequested } + }, + loadingLayer = new LoadingLayer(true), + } + }, + } } - } - }, + }, + } }; // scroll selected room into view on selection. From dfe7cc40a9a39d113e9f1362124e54871dccc3f7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 14 Jul 2021 18:55:01 +0900 Subject: [PATCH 036/961] Move create room button into the lounge --- .../Multiplayer/TestSceneMultiplayer.cs | 6 +-- .../Navigation/TestSceneScreenNavigation.cs | 4 +- .../Lounge/Components/DrawableRoom.cs | 4 +- .../Lounge/Components/FilterControl.cs | 4 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 41 +++++++++++++++++-- .../CreateMultiplayerMatchButton.cs | 1 + .../OnlinePlay/Multiplayer/Multiplayer.cs | 11 ----- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 19 +++++++-- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 30 -------------- .../Playlists/CreatePlaylistsRoomButton.cs | 1 + .../Screens/OnlinePlay/Playlists/Playlists.cs | 9 ---- .../Playlists/PlaylistsLoungeSubScreen.cs | 13 ++++++ 12 files changed, 79 insertions(+), 64 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 7673efb78f..2808127bb8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -249,10 +249,8 @@ namespace osu.Game.Tests.Visual.Multiplayer private void createRoom(Func room) { - AddStep("open room", () => - { - multiplayerScreen.OpenNewRoom(room()); - }); + AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().OpenNewRoom(room())); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddWaitStep("wait for transition", 2); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 52401d32e5..72d01ddd2a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -16,6 +16,7 @@ using osu.Game.Overlays.Toolbar; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.Select; @@ -316,7 +317,8 @@ namespace osu.Game.Tests.Visual.Navigation PushAndConfirm(() => multiplayer = new TestMultiplayer()); - AddStep("open room", () => multiplayer.OpenNewRoom()); + AddUntilStep("wait for lounge", () => multiplayer.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayer.ChildrenOfType().Single().OpenNewRoom()); AddStep("press back button", () => Game.ChildrenOfType().First().Action()); AddWaitStep("wait two frames", 2); } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 441b33abf0..9bfec72942 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private Drawable selectionBox; [Resolved(canBeNull: true)] - private OnlinePlayScreen parentScreen { get; set; } + private LoungeSubScreen loungeScreen { get; set; } [Resolved] private BeatmapManager beatmaps { get; set; } @@ -408,7 +408,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { new OsuMenuItem("Create copy", MenuItemType.Standard, () => { - parentScreen?.OpenNewRoom(Room.CreateCopy()); + loungeScreen?.OpenNewRoom(Room.CreateCopy()); }) }; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs index 36fba68a0c..e2f02fca68 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs @@ -48,7 +48,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Filters = new FillFlowContainer { - RelativeSizeAxes = Axes.Both, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10), Child = statusDropdown = new SlimEnumDropdown diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 068bc34a6c..115dddafec 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -18,6 +18,7 @@ using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; +using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge @@ -29,11 +30,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); + protected Container Buttons { get; } = new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both + }; + private readonly IBindable initialRoomsReceived = new Bindable(); private readonly IBindable operationInProgress = new Bindable(); private FilterControl filter; - private Container content; private LoadingLayer loadingLayer; [Resolved] @@ -63,7 +70,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Colour = Color4.Black, Alpha = 0.5f, }, - content = new Container + new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding @@ -84,7 +91,21 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { new Drawable[] { - filter = CreateFilterControl().With(d => d.Depth = -1), + new Container + { + RelativeSizeAxes = Axes.X, + Height = 70, + Depth = -1, + Children = new Drawable[] + { + filter = CreateFilterControl(), + Buttons.WithChild(CreateNewRoomButton().With(d => + { + d.Size = new Vector2(150, 25); + d.Action = () => OpenNewRoom(); + })) + } + } }, null, new Drawable[] @@ -216,6 +237,20 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected abstract FilterControl CreateFilterControl(); + /// + /// Creates and opens the newly-created room. + /// + /// An optional template to use when creating the room. + public void OpenNewRoom(Room room = null) => Open(room ?? CreateNewRoom()); + + protected abstract OsuButton CreateNewRoomButton(); + + /// + /// Creates a new room. + /// + /// The created . + protected abstract Room CreateNewRoom(); + protected abstract RoomSubScreen CreateRoomSubScreen(Room room); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs index cc51b5b691..edf846f0f8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs @@ -23,6 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void load() { Triangles.TriangleScale = 1.5f; + SpriteText.Font = SpriteText.Font.With(size: 14); Text = "Create room"; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index dbac826954..45928505bb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -4,9 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Logging; using osu.Framework.Screens; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; @@ -54,19 +52,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})"); } - protected override Room CreateNewRoom() => - new Room - { - Name = { Value = $"{API.LocalUser}'s awesome room" }, - Category = { Value = RoomCategory.Realtime } - }; - protected override string ScreenTitle => "Multiplayer"; protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager(); protected override LoungeSubScreen CreateLounge() => new MultiplayerLoungeSubScreen(); - - protected override OsuButton CreateNewMultiplayerGameButton() => new CreateMultiplayerMatchButton(); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 4d20652465..dd5290f127 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -3,6 +3,8 @@ using osu.Framework.Allocation; using osu.Framework.Logging; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge; @@ -13,13 +15,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerLoungeSubScreen : LoungeSubScreen { - protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl(); - - protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); + [Resolved] + private IAPIProvider api { get; set; } [Resolved] private MultiplayerClient client { get; set; } + protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl(); + + protected override OsuButton CreateNewRoomButton() => new CreateMultiplayerMatchButton(); + + protected override Room CreateNewRoom() => new Room + { + Name = { Value = $"{api.LocalUser}'s awesome room" }, + Category = { Value = RoomCategory.Realtime } + }; + + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); + public override void Open(Room room) { if (!client.IsConnected.Value) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index ceee002c6e..3a229ecd4a 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -12,7 +12,6 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.Rooms; @@ -23,7 +22,6 @@ using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; -using osuTK; namespace osu.Game.Screens.OnlinePlay { @@ -38,7 +36,6 @@ namespace osu.Game.Screens.OnlinePlay private readonly MultiplayerWaveContainer waves; - private readonly OsuButton createButton; private readonly LoungeSubScreen loungeSubScreen; private readonly ScreenStack screenStack; @@ -132,18 +129,6 @@ namespace osu.Game.Screens.OnlinePlay } }, new Header(ScreenTitle, screenStack), - createButton = CreateNewMultiplayerGameButton().With(button => - { - button.Anchor = Anchor.TopRight; - button.Origin = Anchor.TopRight; - button.Size = new Vector2(150, Header.HEIGHT - 20); - button.Margin = new MarginPadding - { - Top = 10, - Right = 10 + HORIZONTAL_OVERFLOW_PADDING, - }; - button.Action = () => OpenNewRoom(); - }), RoomManager = CreateRoomManager(), ongoingOperationTracker = new OngoingOperationTracker() } @@ -278,18 +263,6 @@ namespace osu.Game.Screens.OnlinePlay logo.Delay(WaveContainer.DISAPPEAR_DURATION / 2).FadeOut(); } - /// - /// Creates and opens the newly-created room. - /// - /// An optional template to use when creating the room. - public void OpenNewRoom(Room room = null) => loungeSubScreen.Open(room ?? CreateNewRoom()); - - /// - /// Creates a new room. - /// - /// The created . - protected abstract Room CreateNewRoom(); - private void screenPushed(IScreen lastScreen, IScreen newScreen) { subScreenChanged(lastScreen, newScreen); @@ -325,7 +298,6 @@ namespace osu.Game.Screens.OnlinePlay ((IBindable)Activity).BindTo(newOsuScreen.Activity); UpdatePollingRate(isIdle.Value); - createButton.FadeTo(newScreen is LoungeSubScreen ? 1 : 0, 200); } protected IScreen CurrentSubScreen => screenStack.CurrentScreen; @@ -336,8 +308,6 @@ namespace osu.Game.Screens.OnlinePlay protected abstract LoungeSubScreen CreateLounge(); - protected abstract OsuButton CreateNewMultiplayerGameButton(); - private class MultiplayerWaveContainer : WaveContainer { protected override bool StartHidden => true; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs index fcb773f8be..a2c649f10b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs @@ -12,6 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private void load() { Triangles.TriangleScale = 1.5f; + SpriteText.Font = SpriteText.Font.With(size: 14); Text = "Create playlist"; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index 5b132c97fd..6a78e24ba1 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -3,8 +3,6 @@ using osu.Framework.Logging; using osu.Framework.Screens; -using osu.Game.Graphics.UserInterface; -using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Match; @@ -46,17 +44,10 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})"); } - protected override Room CreateNewRoom() - { - return new Room { Name = { Value = $"{API.LocalUser}'s awesome playlist" } }; - } - protected override string ScreenTitle => "Playlists"; protected override RoomManager CreateRoomManager() => new PlaylistsRoomManager(); protected override LoungeSubScreen CreateLounge() => new PlaylistsLoungeSubScreen(); - - protected override OsuButton CreateNewMultiplayerGameButton() => new CreatePlaylistsRoomButton(); } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index bfbff4240c..21113af828 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -1,6 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; @@ -10,8 +13,18 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public class PlaylistsLoungeSubScreen : LoungeSubScreen { + [Resolved] + private IAPIProvider api { get; set; } + protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl(); + protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton(); + + protected override Room CreateNewRoom() + { + return new Room { Name = { Value = $"{api.LocalUser}'s awesome playlist" } }; + } + protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room); } } From 283d953c4fc5da054b875c4c958ce75c238740fd Mon Sep 17 00:00:00 2001 From: aitani9 <55509723+aitani9@users.noreply.github.com> Date: Wed, 21 Jul 2021 14:07:00 -0700 Subject: [PATCH 037/961] Fix blinds moving when barrel roll mod is active --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 35 +++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 636cd63c69..f37058564e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,6 +2,7 @@ // 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; @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield.HitObjectContainer, drawableRuleset.Beatmap)); + drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield, drawableRuleset.Beatmap, drawableRuleset.Mods)); } public void ApplyToHealthProcessor(HealthProcessor healthProcessor) @@ -67,6 +68,8 @@ namespace osu.Game.Rulesets.Osu.Mods private readonly CompositeDrawable restrictTo; + private readonly bool barrelRollActive; + /// /// /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. @@ -80,13 +83,24 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float leniency = 0.1f; - public DrawableOsuBlinds(CompositeDrawable restrictTo, Beatmap beatmap) + public DrawableOsuBlinds(CompositeDrawable restrictTo, Beatmap beatmap, IEnumerable mods) { this.restrictTo = restrictTo; this.beatmap = beatmap; targetBreakMultiplier = 0; easing = 1; + + barrelRollActive = false; + + foreach (Mod mod in mods) + { + if (mod is OsuModBarrelRoll) + { + barrelRollActive = true; + break; + } + } } [BackgroundDependencyLoader] @@ -128,8 +142,21 @@ namespace osu.Game.Rulesets.Osu.Mods protected override void Update() { - float start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; - float end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + float start, end; + + if (barrelRollActive) + { + float origin = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X; + float halfDiagonal = MathF.Sqrt(MathF.Pow(restrictTo.DrawWidth / 2, 2) + MathF.Pow(restrictTo.DrawHeight / 2, 2)); + + start = origin - halfDiagonal; + end = origin + halfDiagonal; + } + else + { + start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; + end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + } float rawWidth = end - start; From e6b28e1386a481ee8e06aef41ae30ef1fae61370 Mon Sep 17 00:00:00 2001 From: aitani9 <55509723+aitani9@users.noreply.github.com> Date: Thu, 22 Jul 2021 14:01:31 -0700 Subject: [PATCH 038/961] Rename `origin` to `center` for clarity --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index f37058564e..c4872aaf64 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -146,11 +146,11 @@ namespace osu.Game.Rulesets.Osu.Mods if (barrelRollActive) { - float origin = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X; + float center = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X; float halfDiagonal = MathF.Sqrt(MathF.Pow(restrictTo.DrawWidth / 2, 2) + MathF.Pow(restrictTo.DrawHeight / 2, 2)); - start = origin - halfDiagonal; - end = origin + halfDiagonal; + start = center - halfDiagonal; + end = center + halfDiagonal; } else { From 80cb7c77b911f380a7fd558d375509bc3e729bf4 Mon Sep 17 00:00:00 2001 From: aitani9 <55509723+aitani9@users.noreply.github.com> Date: Thu, 22 Jul 2021 14:04:01 -0700 Subject: [PATCH 039/961] Calculate the diagonal length using `Vector2.LengthFast` instead of manually --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index c4872aaf64..09d73566a1 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -147,7 +147,7 @@ namespace osu.Game.Rulesets.Osu.Mods if (barrelRollActive) { float center = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X; - float halfDiagonal = MathF.Sqrt(MathF.Pow(restrictTo.DrawWidth / 2, 2) + MathF.Pow(restrictTo.DrawHeight / 2, 2)); + float halfDiagonal = (restrictTo.DrawSize / 2).LengthFast; start = center - halfDiagonal; end = center + halfDiagonal; From 715f3e3f7c1240baed2b64c2c096923f9fcec180 Mon Sep 17 00:00:00 2001 From: aitani9 <55509723+aitani9@users.noreply.github.com> Date: Thu, 22 Jul 2021 14:07:41 -0700 Subject: [PATCH 040/961] Make blinds move correctly whenever the playfield is rotated --- osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs | 31 +++++++--------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs index 09d73566a1..3102db270e 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModBlinds.cs @@ -2,13 +2,13 @@ // 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.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Objects; @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Mods public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) { - drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield, drawableRuleset.Beatmap, drawableRuleset.Mods)); + drawableRuleset.Overlays.Add(blinds = new DrawableOsuBlinds(drawableRuleset.Playfield, drawableRuleset.Beatmap)); } public void ApplyToHealthProcessor(HealthProcessor healthProcessor) @@ -68,8 +68,6 @@ namespace osu.Game.Rulesets.Osu.Mods private readonly CompositeDrawable restrictTo; - private readonly bool barrelRollActive; - /// /// /// Percentage of playfield to extend blinds over. Basically moves the origin points where the blinds start. @@ -83,24 +81,13 @@ namespace osu.Game.Rulesets.Osu.Mods /// private const float leniency = 0.1f; - public DrawableOsuBlinds(CompositeDrawable restrictTo, Beatmap beatmap, IEnumerable mods) + public DrawableOsuBlinds(CompositeDrawable restrictTo, Beatmap beatmap) { this.restrictTo = restrictTo; this.beatmap = beatmap; targetBreakMultiplier = 0; easing = 1; - - barrelRollActive = false; - - foreach (Mod mod in mods) - { - if (mod is OsuModBarrelRoll) - { - barrelRollActive = true; - break; - } - } } [BackgroundDependencyLoader] @@ -144,7 +131,12 @@ namespace osu.Game.Rulesets.Osu.Mods { float start, end; - if (barrelRollActive) + if (Precision.AlmostEquals(restrictTo.Rotation, 0)) + { + start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; + end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; + } + else { float center = restrictTo.ToSpaceOfOtherDrawable(restrictTo.OriginPosition, Parent).X; float halfDiagonal = (restrictTo.DrawSize / 2).LengthFast; @@ -152,11 +144,6 @@ namespace osu.Game.Rulesets.Osu.Mods start = center - halfDiagonal; end = center + halfDiagonal; } - else - { - start = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopLeft).X; - end = Parent.ToLocalSpace(restrictTo.ScreenSpaceDrawQuad.TopRight).X; - } float rawWidth = end - start; From 8b3feaabfcab105dc49ba0861e6f1ccbf528dd4c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Aug 2021 20:07:42 +0900 Subject: [PATCH 041/961] Fix more compile errors --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 2 +- osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6681703311..893d99fb9d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -401,7 +401,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void createRoom(Func room) { AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().OpenNewRoom(room())); + AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().Open(room())); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddWaitStep("wait for transition", 2); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index fa2b2b363f..3c65f46c79 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -318,7 +318,7 @@ namespace osu.Game.Tests.Visual.Navigation PushAndConfirm(() => multiplayer = new TestMultiplayer()); AddUntilStep("wait for lounge", () => multiplayer.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayer.ChildrenOfType().Single().OpenNewRoom()); + AddStep("open room", () => multiplayer.ChildrenOfType().Single().Open()); AddStep("press back button", () => Game.ChildrenOfType().First().Action()); AddWaitStep("wait two frames", 2); } From 56ded4fde640d5589af877e701f1b31bd2deb761 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Aug 2021 20:32:51 +0900 Subject: [PATCH 042/961] Fix DrawableRoom test scene --- .../Multiplayer/TestSceneDrawableRoom.cs | 131 ++++++++++-------- 1 file changed, 70 insertions(+), 61 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index c69890ba33..faabed0e17 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -4,6 +4,8 @@ using System; using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -19,49 +21,78 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneDrawableRoom : OsuTestScene { - public TestSceneDrawableRoom() + [Cached] + private readonly Bindable selectedRoom = new Bindable(); + + [Test] + public void TestMultipleStatuses() { - Child = new FillFlowContainer + AddStep("create rooms", () => { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.9f), - Spacing = new Vector2(10), - Children = new Drawable[] + Child = new FillFlowContainer { - createDrawableRoom(new Room + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.9f), + Spacing = new Vector2(10), + Children = new Drawable[] { - Name = { Value = "Room 1" }, - Status = { Value = new RoomStatusOpen() }, - EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, - }), - createDrawableRoom(new Room - { - Name = { Value = "Room 2" }, - Status = { Value = new RoomStatusPlaying() }, - EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, - }), - createDrawableRoom(new Room - { - Name = { Value = "Room 3" }, - Status = { Value = new RoomStatusEnded() }, - EndDate = { Value = DateTimeOffset.Now }, - }), - createDrawableRoom(new Room - { - Name = { Value = "Room 4 (realtime)" }, - Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime }, - }), - createDrawableRoom(new Room - { - Name = { Value = "Room 4 (spotlight)" }, - Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Spotlight }, - }), - } - }; + createDrawableRoom(new Room + { + Name = { Value = "Room 1" }, + Status = { Value = new RoomStatusOpen() }, + EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + }), + createDrawableRoom(new Room + { + Name = { Value = "Room 2" }, + Status = { Value = new RoomStatusPlaying() }, + EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + }), + createDrawableRoom(new Room + { + Name = { Value = "Room 3" }, + Status = { Value = new RoomStatusEnded() }, + EndDate = { Value = DateTimeOffset.Now }, + }), + createDrawableRoom(new Room + { + Name = { Value = "Room 4 (realtime)" }, + Status = { Value = new RoomStatusOpen() }, + Category = { Value = RoomCategory.Realtime }, + }), + createDrawableRoom(new Room + { + Name = { Value = "Room 4 (spotlight)" }, + Status = { Value = new RoomStatusOpen() }, + Category = { Value = RoomCategory.Spotlight }, + }), + } + }; + }); + } + + [Test] + public void TestEnableAndDisablePassword() + { + DrawableRoom drawableRoom = null; + Room room = null; + + AddStep("create room", () => Child = drawableRoom = createDrawableRoom(room = new Room + { + Name = { Value = "Room with password" }, + Status = { Value = new RoomStatusOpen() }, + Category = { Value = RoomCategory.Realtime }, + })); + + AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); + + AddStep("set password", () => room.Password.Value = "password"); + AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType().Single().Alpha)); + + AddStep("unset password", () => room.Password.Value = string.Empty); + AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); } private DrawableRoom createDrawableRoom(Room room) @@ -82,27 +113,5 @@ namespace osu.Game.Tests.Visual.Multiplayer return drawableRoom; } - - [Test] - public void TestEnableAndDisablePassword() - { - DrawableRoom drawableRoom = null; - Room room = null; - - AddStep("create room", () => Child = drawableRoom = new DrawableRoom(room = new Room - { - Name = { Value = "Room with password" }, - Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime }, - }) { MatchingFilter = true }); - - AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); - - AddStep("set password", () => room.Password.Value = "password"); - AddAssert("password icon visible", () => Precision.AlmostEquals(1, drawableRoom.ChildrenOfType().Single().Alpha)); - - AddStep("unset password", () => room.Password.Value = string.Empty); - AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); - } } } From 50f6632051de4d0a0d609eb90e5c4ae9b93107dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 3 Aug 2021 20:38:50 +0900 Subject: [PATCH 043/961] Fix duplicate RoomManager --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 5ec9202759..fee612c0a5 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -140,7 +140,7 @@ namespace osu.Game.Screens.OnlinePlay } }, new Header(ScreenTitle, screenStack), - RoomManager = CreateRoomManager(), + RoomManager, ongoingOperationTracker } }; From c06fffb56ac73219ba0f796fac0f5f39ac77ba93 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Aug 2021 13:49:13 +0900 Subject: [PATCH 044/961] Increase background image resolution --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index c2955cec94..3112b2cc30 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -190,7 +190,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Colour = Color4Extensions.FromHex(@"#27302E"), }, - new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) + new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) { RelativeSizeAxes = Axes.Both }, From 3b6771ca65514060935b5b34bab8da8d3b31e25e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 4 Aug 2021 22:09:03 +0900 Subject: [PATCH 045/961] Remove todo --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 0b19e2df1c..06c95dcb7d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -359,7 +359,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomCategory.BindTo(Room.Category); roomCategory.BindValueChanged(c => { - // Todo: Tournament category... if (c.NewValue == RoomCategory.Spotlight) specialCategoryPill.Show(); else From a01402664f341be9bc04ffbb9811ee6d40cbbdae Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Jul 2021 05:22:11 +0300 Subject: [PATCH 046/961] Add redesigned star rating display Matching the same design as the one in the latest figma designs. --- .../Beatmaps/Drawables/StarRatingDisplayV2.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs new file mode 100644 index 0000000000..aa411e74bd --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs @@ -0,0 +1,99 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Beatmaps.Drawables +{ + public class StarRatingDisplayV2 : CompositeDrawable, IHasCurrentValue + { + private readonly Box background; + private readonly SpriteIcon starIcon; + private readonly OsuSpriteText starsText; + + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } + + [Resolved] + private OsuColour colours { get; set; } + + [Resolved(canBeNull: true)] + private OverlayColourProvider colourProvider { get; set; } + + /// + /// Creates a new using an already computed . + /// + /// The already computed to display the star difficulty of. + public StarRatingDisplayV2(StarDifficulty starDifficulty) + { + Size = new Vector2(52f, 20f); + + Current.Value = starDifficulty; + + InternalChild = new CircularContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + starIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Right = 30f }, + Icon = FontAwesome.Solid.Star, + Size = new Vector2(8f), + }, + starsText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Left = 10f, Bottom = 1f }, + Font = OsuFont.Torus.With(size: 12f, weight: FontWeight.Bold), + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(c => + { + starsText.Text = c.NewValue.Stars.ToString("0.00"); + + background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); + + starIcon.Colour = c.NewValue.Stars >= 7.5 + ? colourProvider?.Content1 ?? Color4.White + : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); + + starsText.Colour = c.NewValue.Stars >= 7.5 + ? colourProvider?.Content1 ?? Color4.White.Opacity(0.75f) + : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); + }, true); + } + } +} From 6c9ed16b0caa5e29f436d58c388ada3ab34e31b1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 13 Jul 2021 05:29:16 +0300 Subject: [PATCH 047/961] Add visual test scene --- .../TestSceneStarRatingDisplayV2.cs | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs new file mode 100644 index 0000000000..1b85e25e92 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs @@ -0,0 +1,69 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; +using osuTK; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneStarRatingDisplayV2 : OsuTestScene + { + [Test] + public void TestDisplay() + { + AddStep("load displays", () => + { + Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(2f), + Direction = FillDirection.Horizontal, + ChildrenEnumerable = Enumerable.Range(0, 10).Select(i => new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + AutoSizeAxes = Axes.Both, + Spacing = new Vector2(2f), + Direction = FillDirection.Vertical, + ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplayV2(new StarDifficulty(i + j * 0.1f, 0)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }) + }) + }; + }); + } + + [Test] + public void TestChangingStarRatingDisplay() + { + StarRatingDisplayV2 starRating = null; + + AddStep("load display", () => Child = starRating = new StarRatingDisplayV2(new StarDifficulty(5.55, 1)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }); + + AddRepeatStep("set random value", () => + { + starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1); + }, 10); + + AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d => + { + if (starRating != null) + starRating.Current.Value = new StarDifficulty(d, 1); + }); + } + } +} From 19d54ee7510d0a4d594b0897e22fd39e45c3b9e5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 16 Jul 2021 01:59:32 +0300 Subject: [PATCH 048/961] Update light background handling to `Color4.Yellow` instead Confirmed to be the way forward in https://github.com/ppy/osu-web/pull/7855#issuecomment-880959644. --- osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs index aa411e74bd..6154c8e811 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs @@ -86,13 +86,8 @@ namespace osu.Game.Beatmaps.Drawables background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); - starIcon.Colour = c.NewValue.Stars >= 7.5 - ? colourProvider?.Content1 ?? Color4.White - : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); - - starsText.Colour = c.NewValue.Stars >= 7.5 - ? colourProvider?.Content1 ?? Color4.White.Opacity(0.75f) - : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); + starIcon.Colour = c.NewValue.Stars >= 6.5 ? Color4.Yellow : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); + starsText.Colour = c.NewValue.Stars >= 6.5 ? Color4.Yellow : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); }, true); } } From 95b134f3d82ff42868c6726dcd0ad22220efe327 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Jul 2021 05:41:34 +0300 Subject: [PATCH 049/961] Use `OsuColour.Orange1` instead of pure yellow --- osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs index 6154c8e811..5a942cdeee 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs @@ -86,8 +86,8 @@ namespace osu.Game.Beatmaps.Drawables background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); - starIcon.Colour = c.NewValue.Stars >= 6.5 ? Color4.Yellow : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); - starsText.Colour = c.NewValue.Stars >= 6.5 ? Color4.Yellow : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); + starIcon.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); + starsText.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); }, true); } } From 14da5ab813d1d7fe523827a59de535c2846d9298 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Jul 2021 05:43:04 +0300 Subject: [PATCH 050/961] Remove defined size from the star rating display --- osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs index 5a942cdeee..e8961ae414 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs @@ -43,8 +43,6 @@ namespace osu.Game.Beatmaps.Drawables /// The already computed to display the star difficulty of. public StarRatingDisplayV2(StarDifficulty starDifficulty) { - Size = new Vector2(52f, 20f); - Current.Value = starDifficulty; InternalChild = new CircularContainer From 0a8d37defa3a167ae725f62c9ab39799f03449bd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Jul 2021 05:48:38 +0300 Subject: [PATCH 051/961] Test star rating display with multiple sizes --- .../Visual/UserInterface/TestSceneStarRatingDisplayV2.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs index 1b85e25e92..43178bb280 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs @@ -14,8 +14,10 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneStarRatingDisplayV2 : OsuTestScene { - [Test] - public void TestDisplay() + [TestCase(52f, 20f)] + [TestCase(52f, 16f)] + [TestCase(50f, 14f)] + public void TestDisplay(float width, float height) { AddStep("load displays", () => { @@ -37,6 +39,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = new Vector2(width, height), }) }) }; @@ -52,6 +55,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Size = new Vector2(52f, 20f), }); AddRepeatStep("set random value", () => From d4399f10f9b65bb737da9785ceb44a1bf10ef6e7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 17 Jul 2021 06:54:11 +0300 Subject: [PATCH 052/961] Merge both variants of the star rating display --- .../Ranking/TestSceneStarRatingDisplay.cs | 65 --------- ...layV2.cs => TestSceneStarRatingDisplay.cs} | 36 ++++- ...atingDisplayV2.cs => StarRatingDisplay.cs} | 21 ++- .../Components/StarRatingRangeDisplay.cs | 12 +- .../Screens/Play/BeatmapMetadataDisplay.cs | 2 +- .../Expanded/ExpandedPanelMiddleContent.cs | 1 + .../Ranking/Expanded/StarRatingDisplay.cs | 129 ------------------ osu.Game/Screens/Select/BeatmapInfoWedge.cs | 1 - 8 files changed, 56 insertions(+), 211 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs rename osu.Game.Tests/Visual/UserInterface/{TestSceneStarRatingDisplayV2.cs => TestSceneStarRatingDisplay.cs} (66%) rename osu.Game/Beatmaps/Drawables/{StarRatingDisplayV2.cs => StarRatingDisplay.cs} (75%) delete mode 100644 osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs deleted file mode 100644 index 566452249f..0000000000 --- a/osu.Game.Tests/Visual/Ranking/TestSceneStarRatingDisplay.cs +++ /dev/null @@ -1,65 +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 NUnit.Framework; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Screens.Ranking.Expanded; -using osuTK; - -namespace osu.Game.Tests.Visual.Ranking -{ - public class TestSceneStarRatingDisplay : OsuTestScene - { - [Test] - public void TestDisplay() - { - AddStep("load displays", () => Child = new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - ChildrenEnumerable = new[] - { - 1.23, - 2.34, - 3.45, - 4.56, - 5.67, - 6.78, - 10.11, - }.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0)) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }) - }); - } - - [Test] - public void TestChangingStarRatingDisplay() - { - StarRatingDisplay starRating = null; - - AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1)) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(3f), - }); - - AddRepeatStep("set random value", () => - { - starRating.Current.Value = new StarDifficulty(RNG.NextDouble(0.0, 11.0), 1); - }, 10); - - AddSliderStep("set exact stars", 0.0, 11.0, 5.55, d => - { - if (starRating != null) - starRating.Current.Value = new StarDifficulty(d, 1); - }); - } - } -} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs similarity index 66% rename from osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs rename to osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 43178bb280..4c65500fbe 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplayV2.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -12,12 +12,36 @@ using osuTK; namespace osu.Game.Tests.Visual.UserInterface { - public class TestSceneStarRatingDisplayV2 : OsuTestScene + public class TestSceneStarRatingDisplay : OsuTestScene { + [Test] + public void TestOldColoursDisplay() + { + AddStep("load displays", () => Child = new FillFlowContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + ChildrenEnumerable = new[] + { + 1.23, + 2.34, + 3.45, + 4.56, + 5.67, + 6.78, + 10.11, + }.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + }) + }); + } + [TestCase(52f, 20f)] [TestCase(52f, 16f)] [TestCase(50f, 14f)] - public void TestDisplay(float width, float height) + public void TestNewColoursDisplay(float width, float height) { AddStep("load displays", () => { @@ -35,7 +59,7 @@ namespace osu.Game.Tests.Visual.UserInterface AutoSizeAxes = Axes.Both, Spacing = new Vector2(2f), Direction = FillDirection.Vertical, - ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplayV2(new StarDifficulty(i + j * 0.1f, 0)) + ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i + j * 0.1f, 0), true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -47,11 +71,11 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestChangingStarRatingDisplay() + public void TestChangingStarRatingDisplay([Values(false, true)] bool useNewColours) { - StarRatingDisplayV2 starRating = null; + StarRatingDisplay starRating = null; - AddStep("load display", () => Child = starRating = new StarRatingDisplayV2(new StarDifficulty(5.55, 1)) + AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1), useNewColours) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs similarity index 75% rename from osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs rename to osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index e8961ae414..ed751c66de 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplayV2.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -17,8 +17,12 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class StarRatingDisplayV2 : CompositeDrawable, IHasCurrentValue + /// + /// A pill that displays the star rating of a beatmap. + /// + public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue { + private readonly bool useNewDifficultyColours; private readonly Box background; private readonly SpriteIcon starIcon; private readonly OsuSpriteText starsText; @@ -38,13 +42,18 @@ namespace osu.Game.Beatmaps.Drawables private OverlayColourProvider colourProvider { get; set; } /// - /// Creates a new using an already computed . + /// Creates a new using an already computed . /// - /// The already computed to display the star difficulty of. - public StarRatingDisplayV2(StarDifficulty starDifficulty) + /// The already computed to display. + /// Use the new spectrum-based difficulty colours for the display, rather than the old. + public StarRatingDisplay(StarDifficulty starDifficulty, bool useNewDifficultyColours = false) { + this.useNewDifficultyColours = useNewDifficultyColours; + Current.Value = starDifficulty; + Size = new Vector2(52f, 20f); + InternalChild = new CircularContainer { Masking = true, @@ -82,7 +91,9 @@ namespace osu.Game.Beatmaps.Drawables { starsText.Text = c.NewValue.Stars.ToString("0.00"); - background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); + background.Colour = useNewDifficultyColours + ? colours.ForStarDifficulty(c.NewValue.Stars) + : colours.ForDifficultyRating(c.NewValue.DifficultyRating); starIcon.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); starsText.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 8c1b10e3bd..6f5e48f09c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -8,14 +8,16 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; -using osu.Game.Screens.Ranking.Expanded; using osuTK; namespace osu.Game.Screens.OnlinePlay.Components { public class StarRatingRangeDisplay : OnlinePlayComposite { + private readonly bool useNewDifficultyColours; + [Resolved] private OsuColour colours { get; set; } @@ -24,8 +26,10 @@ namespace osu.Game.Screens.OnlinePlay.Components private StarRatingDisplay maxDisplay; private Drawable maxBackground; - public StarRatingRangeDisplay() + public StarRatingRangeDisplay(bool useNewDifficultyColours = false) { + this.useNewDifficultyColours = useNewDifficultyColours; + AutoSizeAxes = Axes.Both; } @@ -62,8 +66,8 @@ namespace osu.Game.Screens.OnlinePlay.Components AutoSizeAxes = Axes.Both, Children = new Drawable[] { - minDisplay = new StarRatingDisplay(default), - maxDisplay = new StarRatingDisplay(default) + minDisplay = new StarRatingDisplay(default) { Size = new Vector2(52f, 16f) }, + maxDisplay = new StarRatingDisplay(default) { Size = new Vector2(52f, 16f) } } } }; diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs index 4265a83ce1..d77673580a 100644 --- a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -10,12 +10,12 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; 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 osu.Game.Screens.Ranking.Expanded; using osuTK; namespace osu.Game.Screens.Play diff --git a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs index e10fe5726d..bcb5e7999f 100644 --- a/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs +++ b/osu.Game/Screens/Ranking/Expanded/ExpandedPanelMiddleContent.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; diff --git a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs b/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs deleted file mode 100644 index 2b86100be8..0000000000 --- a/osu.Game/Screens/Ranking/Expanded/StarRatingDisplay.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Globalization; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Beatmaps; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osuTK; -using osuTK.Graphics; - -namespace osu.Game.Screens.Ranking.Expanded -{ - /// - /// A pill that displays the star rating of a . - /// - public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue - { - private Box background; - private FillFlowContainer content; - private OsuTextFlowContainer textFlow; - - [Resolved] - private OsuColour colours { get; set; } - - private readonly BindableWithCurrent current = new BindableWithCurrent(); - - public Bindable Current - { - get => current.Current; - set => current.Current = value; - } - - /// - /// Creates a new using an already computed . - /// - /// The already computed to display the star difficulty of. - public StarRatingDisplay(StarDifficulty starDifficulty) - { - Current.Value = starDifficulty; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours, BeatmapDifficultyCache difficultyCache) - { - AutoSizeAxes = Axes.Both; - - InternalChildren = new Drawable[] - { - new CircularContainer - { - RelativeSizeAxes = Axes.Both, - Masking = true, - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - } - }, - content = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 8, Vertical = 4 }, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(2, 0), - Children = new Drawable[] - { - new SpriteIcon - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Size = new Vector2(7), - Icon = FontAwesome.Solid.Star, - }, - textFlow = new OsuTextFlowContainer(s => s.Font = OsuFont.Numeric.With(weight: FontWeight.Black)) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - TextAnchor = Anchor.BottomLeft, - } - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Current.BindValueChanged(_ => updateDisplay(), true); - } - - private void updateDisplay() - { - var starRatingParts = Current.Value.Stars.ToString("0.00", CultureInfo.InvariantCulture).Split('.'); - string wholePart = starRatingParts[0]; - string fractionPart = starRatingParts[1]; - string separator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; - - var stars = Current.Value.Stars; - - background.Colour = colours.ForStarDifficulty(stars); - content.Colour = stars >= 6.5 ? colours.Orange1 : Color4.Black; - - textFlow.Clear(); - textFlow.AddText($"{wholePart}", s => - { - s.Font = s.Font.With(size: 14); - s.UseFullGlyphHeight = false; - }); - - textFlow.AddText($"{separator}{fractionPart}", s => - { - s.Font = s.Font.With(size: 7); - s.UseFullGlyphHeight = false; - }); - } - } -} diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3779523094..67eb8220f7 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -28,7 +28,6 @@ using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; -using osu.Game.Screens.Ranking.Expanded; using osu.Game.Graphics.Containers; namespace osu.Game.Screens.Select From 42370e48ec3b06e4861cb56175f521faece1f033 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 18 Jul 2021 08:20:06 +0300 Subject: [PATCH 053/961] Disable shadow on star display text --- osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index ed751c66de..96e830ccc3 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -78,6 +78,7 @@ namespace osu.Game.Beatmaps.Drawables Origin = Anchor.Centre, Margin = new MarginPadding { Left = 10f, Bottom = 1f }, Font = OsuFont.Torus.With(size: 12f, weight: FontWeight.Bold), + Shadow = false, } } }; From 284fa496463bc3c5d718b141bf1dd81293705845 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 18 Jul 2021 08:20:22 +0300 Subject: [PATCH 054/961] Bring margins of components closer to existing designs --- osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 96e830ccc3..2b555cc096 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -68,7 +68,7 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding { Right = 30f }, + Margin = new MarginPadding { Right = 26.5f }, Icon = FontAwesome.Solid.Star, Size = new Vector2(8f), }, @@ -76,7 +76,7 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding { Left = 10f, Bottom = 1f }, + Margin = new MarginPadding { Left = 10f, Bottom = 1.5f }, Font = OsuFont.Torus.With(size: 12f, weight: FontWeight.Bold), Shadow = false, } From 7f9af0ae658331cc424b4572791ea5312bc63013 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 18 Jul 2021 08:21:27 +0300 Subject: [PATCH 055/961] Scale up "changing display" test cases --- .../Visual/UserInterface/TestSceneStarRatingDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 4c65500fbe..88f43cd701 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Visual.UserInterface { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(52f, 20f), + Scale = new Vector2(3f), }); AddRepeatStep("set random value", () => From b2332eb5b38091c6ea175cb27ead4b3d8d04c06f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 4 Aug 2021 17:06:07 +0300 Subject: [PATCH 056/961] Use new difficulty colours permanently --- .../TestSceneStarRatingDisplay.cs | 32 +++---------------- .../Beatmaps/Drawables/StarRatingDisplay.cs | 10 ++---- .../Components/StarRatingRangeDisplay.cs | 6 +--- 3 files changed, 7 insertions(+), 41 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 88f43cd701..2f3593c062 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -14,34 +14,10 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneStarRatingDisplay : OsuTestScene { - [Test] - public void TestOldColoursDisplay() - { - AddStep("load displays", () => Child = new FillFlowContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - ChildrenEnumerable = new[] - { - 1.23, - 2.34, - 3.45, - 4.56, - 5.67, - 6.78, - 10.11, - }.Select(starRating => new StarRatingDisplay(new StarDifficulty(starRating, 0)) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre - }) - }); - } - [TestCase(52f, 20f)] [TestCase(52f, 16f)] [TestCase(50f, 14f)] - public void TestNewColoursDisplay(float width, float height) + public void TestDisplay(float width, float height) { AddStep("load displays", () => { @@ -59,7 +35,7 @@ namespace osu.Game.Tests.Visual.UserInterface AutoSizeAxes = Axes.Both, Spacing = new Vector2(2f), Direction = FillDirection.Vertical, - ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i + j * 0.1f, 0), true) + ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i + j * 0.1f, 0)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -71,11 +47,11 @@ namespace osu.Game.Tests.Visual.UserInterface } [Test] - public void TestChangingStarRatingDisplay([Values(false, true)] bool useNewColours) + public void TestChangingStarRatingDisplay() { StarRatingDisplay starRating = null; - AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1), useNewColours) + AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 2b555cc096..0520cea17a 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -22,7 +22,6 @@ namespace osu.Game.Beatmaps.Drawables /// public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue { - private readonly bool useNewDifficultyColours; private readonly Box background; private readonly SpriteIcon starIcon; private readonly OsuSpriteText starsText; @@ -45,11 +44,8 @@ namespace osu.Game.Beatmaps.Drawables /// Creates a new using an already computed . /// /// The already computed to display. - /// Use the new spectrum-based difficulty colours for the display, rather than the old. - public StarRatingDisplay(StarDifficulty starDifficulty, bool useNewDifficultyColours = false) + public StarRatingDisplay(StarDifficulty starDifficulty) { - this.useNewDifficultyColours = useNewDifficultyColours; - Current.Value = starDifficulty; Size = new Vector2(52f, 20f); @@ -92,9 +88,7 @@ namespace osu.Game.Beatmaps.Drawables { starsText.Text = c.NewValue.Stars.ToString("0.00"); - background.Colour = useNewDifficultyColours - ? colours.ForStarDifficulty(c.NewValue.Stars) - : colours.ForDifficultyRating(c.NewValue.DifficultyRating); + background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); starIcon.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); starsText.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 6f5e48f09c..867fa88352 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -16,8 +16,6 @@ namespace osu.Game.Screens.OnlinePlay.Components { public class StarRatingRangeDisplay : OnlinePlayComposite { - private readonly bool useNewDifficultyColours; - [Resolved] private OsuColour colours { get; set; } @@ -26,10 +24,8 @@ namespace osu.Game.Screens.OnlinePlay.Components private StarRatingDisplay maxDisplay; private Drawable maxBackground; - public StarRatingRangeDisplay(bool useNewDifficultyColours = false) + public StarRatingRangeDisplay() { - this.useNewDifficultyColours = useNewDifficultyColours; - AutoSizeAxes = Axes.Both; } From b63d47259480ddc46579b76cb8505102f249000c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 4 Aug 2021 18:17:02 +0300 Subject: [PATCH 057/961] Adjust font size to match designs Looks silly when using `12f`, I've added a todo comment so that this specific case does not get forgotten when CSS-compatible font sizing gets supported. The todo comment may not be 100% required but very unsure about silently changing it and forgetting about it. --- osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 0520cea17a..2c40aebbe1 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -64,7 +64,7 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding { Right = 26.5f }, + Margin = new MarginPadding { Right = 30f }, Icon = FontAwesome.Solid.Star, Size = new Vector2(8f), }, @@ -72,8 +72,10 @@ namespace osu.Game.Beatmaps.Drawables { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding { Left = 10f, Bottom = 1.5f }, - Font = OsuFont.Torus.With(size: 12f, weight: FontWeight.Bold), + Margin = new MarginPadding { Left = 10f, Bottom = 2f }, + // todo: this should be size: 12f, but to match up with the design, it needs to be 14.4f + // see https://github.com/ppy/osu-framework/issues/3271. + Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold), Shadow = false, } } From c56b6a5379cb97e41da9caae4fa0b6f9b2176ed4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 20:52:40 +0900 Subject: [PATCH 058/961] Fix compilation failure --- osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index e19665497d..a8fda19c60 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -17,6 +17,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Screens.OnlinePlay.Multiplayer.Participants; @@ -150,10 +151,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private void createRoom(Func room) { - AddStep("open room", () => - { - multiplayerScreen.OpenNewRoom(room()); - }); + AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().Open(room())); AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); AddWaitStep("wait for transition", 2); From 5521f38cfbc240f222a79c949512a8d87cd56ead Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 20:56:09 +0900 Subject: [PATCH 059/961] Adjust spacing --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 06c95dcb7d..9d1f495ab9 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -235,7 +235,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), + Spacing = new Vector2(5), Children = new Drawable[] { new RoomStatusPill From bd394d937750f3b82aa12e15ee169e9ef5fa7db0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 20:56:14 +0900 Subject: [PATCH 060/961] Fix pluralisation --- .../Multiplayer/TestSceneDrawableRoom.cs | 47 +++++++++++++++++++ .../Lounge/Components/PlaylistCountPill.cs | 4 +- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index faabed0e17..adada5890e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -13,7 +13,9 @@ using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Tests.Beatmaps; using osu.Game.Users; using osuTK; @@ -43,12 +45,57 @@ namespace osu.Game.Tests.Visual.Multiplayer Name = { Value = "Room 1" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + Playlist = + { + new PlaylistItem + { + Beatmap = + { + Value = new TestBeatmap(new OsuRuleset().RulesetInfo) + { + BeatmapInfo = + { + StarDifficulty = 2.5 + } + }.BeatmapInfo, + } + } + } }), createDrawableRoom(new Room { Name = { Value = "Room 2" }, Status = { Value = new RoomStatusPlaying() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, + Playlist = + { + new PlaylistItem + { + Beatmap = + { + Value = new TestBeatmap(new OsuRuleset().RulesetInfo) + { + BeatmapInfo = + { + StarDifficulty = 2.5 + } + }.BeatmapInfo, + } + }, + new PlaylistItem + { + Beatmap = + { + Value = new TestBeatmap(new OsuRuleset().RulesetInfo) + { + BeatmapInfo = + { + StarDifficulty = 4.5 + } + }.BeatmapInfo, + } + } + } }), createDrawableRoom(new Room { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs index 8d8309fcaa..2fe3c7b668 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistCountPill.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Specialized; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; @@ -46,7 +47,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { count.Clear(); count.AddText(Playlist.Count.ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); - count.AddText(" Maps"); + count.AddText(" "); + count.AddText("Beatmap".ToQuantity(Playlist.Count, ShowQuantityAs.None)); } } } From b8ec1cb9847701aa88de554c35798281b0089b84 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 20:58:51 +0900 Subject: [PATCH 061/961] Hide star rating max display for equal difficulties --- .../Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index b2e35d7020..3b4ac69466 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Screens.Ranking.Expanded; @@ -85,6 +86,7 @@ namespace osu.Game.Screens.OnlinePlay.Components minDisplay.Current.Value = minDifficulty; maxDisplay.Current.Value = maxDifficulty; + maxDisplay.Alpha = Precision.AlmostEquals(minDifficulty.Stars, maxDifficulty.Stars) ? 0 : 1; minBackground.Colour = colours.ForDifficultyRating(minDifficulty.DifficultyRating, true); maxBackground.Colour = colours.ForDifficultyRating(maxDifficulty.DifficultyRating, true); From 2f2e3d736665c50675aff9ab0cd3b7c6cd6d731b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 21:01:21 +0900 Subject: [PATCH 062/961] Use higher res background image --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 9d1f495ab9..ae408f9f84 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -161,7 +161,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Colour = Color4Extensions.FromHex(@"#27302E"), }, - new OnlinePlayBackgroundSprite(BeatmapSetCoverType.List) + new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) { RelativeSizeAxes = Axes.Both }, From 438f0ce7027497816836431b0aaf4d470bd4faef Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 21:02:14 +0900 Subject: [PATCH 063/961] Increase default number of avatars --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index ae408f9f84..146add34b7 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } - private int numberOfAvatars = 3; + private int numberOfAvatars = 7; public int NumberOfAvatars { From 87fd1eaf067919d49edf3513d8438b9e01743a8e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 21:19:23 +0900 Subject: [PATCH 064/961] Explain negative padding --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 146add34b7..08137d1615 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -171,6 +171,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Name = @"Room content", RelativeSizeAxes = Axes.Both, + // This negative padding resolves 1px gaps between this background and the background above. Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, Child = new Container { From c74e620ce9bec562a1aed8af85a1990af291e817 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 21:20:55 +0900 Subject: [PATCH 065/961] Add constant for background colour --- .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 08137d1615..ee0e1b5adc 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -40,6 +40,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private const float transition_duration = 60; private const float height = 100; + private static readonly Color4 background_colour = Color4Extensions.FromHex(@"#27302E"); + public event Action StateChanged; private Drawable selectionBox; @@ -159,7 +161,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), + Colour = background_colour, }, new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) { @@ -189,7 +191,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), + Colour = background_colour, }, new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) { @@ -209,12 +211,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#27302E"), + Colour = background_colour, }, new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(Color4Extensions.FromHex(@"#27302E"), Color4Extensions.FromHex(@"#27302E").Opacity(0.3f)) + Colour = ColourInfo.GradientHorizontal(background_colour, background_colour.Opacity(0.3f)) }, } } From fd6d488657b55d14770aabe8436b456096fd0cf1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 21:40:09 +0900 Subject: [PATCH 066/961] Add thousands separator to rank range pill --- .../Multiplayer/TestSceneRankRangePill.cs | 28 +++++++++++++++++++ .../Lounge/Components/RankRangePill.cs | 7 +++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs index 5e28b3f8e5..9e03743e8d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRankRangePill.cs @@ -63,5 +63,33 @@ namespace osu.Game.Tests.Visual.Multiplayer Client.RemoveUser(API.LocalUser.Value); }); } + + [TestCase(1, 10)] + [TestCase(10, 100)] + [TestCase(100, 1000)] + [TestCase(1000, 10000)] + [TestCase(10000, 100000)] + [TestCase(100000, 1000000)] + [TestCase(1000000, 10000000)] + public void TestRange(int min, int max) + { + AddStep("add users", () => + { + Client.AddUser(new User + { + Id = 2, + Statistics = { GlobalRank = min } + }); + + Client.AddUser(new User + { + Id = 3, + Statistics = { GlobalRank = max } + }); + + // Remove the local user so only the ones above are displayed. + Client.RemoveUser(API.LocalUser.Value); + }); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs index 8f685ba033..42fe0bfecd 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RankRangePill.cs @@ -65,13 +65,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components return; } + int minRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min(); + int maxRank = Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max(); + rankFlow.AddText("#"); - rankFlow.AddText(Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Min().ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); + rankFlow.AddText(minRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold)); rankFlow.AddText(" - "); rankFlow.AddText("#"); - rankFlow.AddText(Room.Users.Select(u => u.User?.Statistics.GlobalRank ?? 0).DefaultIfEmpty(0).Max().ToString(), s => s.Font = s.Font.With(weight: FontWeight.Bold)); + rankFlow.AddText(maxRank.ToString("#,0"), s => s.Font = s.Font.With(weight: FontWeight.Bold)); } } } From 0ea982c036814109f43851716d3fc9124cdfb3ca Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 5 Aug 2021 22:49:41 +0900 Subject: [PATCH 067/961] Update recent participants list to use participant_count --- .../TestSceneRecentParticipantsList.cs | 42 ++++++++++--------- .../Components/RecentParticipantsList.cs | 16 +++---- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index c9959b3467..f05c092dfb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -36,13 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add 50 users", () => { for (int i = 0; i < 50; i++) - { - SelectedRoom.Value.RecentParticipants.Add(new User - { - Id = i, - Username = $"User {i}" - }); - } + addUser(i); }); AddStep("set 3 avatars", () => list.NumberOfAvatars = 3); @@ -60,34 +54,44 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add 50 users", () => { for (int i = 0; i < 50; i++) - { - SelectedRoom.Value.RecentParticipants.Add(new User - { - Id = i, - Username = $"User {i}" - }); - } + addUser(i); }); - AddStep("remove from start", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0)); + AddStep("remove from start", () => removeUserAt(0)); AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("46 hidden users", () => list.ChildrenOfType().Single().Count == 46); - AddStep("remove from end", () => SelectedRoom.Value.RecentParticipants.RemoveAt(SelectedRoom.Value.RecentParticipants.Count - 1)); + AddStep("remove from end", () => removeUserAt(SelectedRoom.Value.RecentParticipants.Count - 1)); AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("45 hidden users", () => list.ChildrenOfType().Single().Count == 45); - AddRepeatStep("remove 45 users", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0), 45); + AddRepeatStep("remove 45 users", () => removeUserAt(0), 45); AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); AddAssert("hidden users bubble hidden", () => list.ChildrenOfType().Single().Alpha < 0.5f); - AddStep("remove another user", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0)); + AddStep("remove another user", () => removeUserAt(0)); AddAssert("2 avatars displayed", () => list.ChildrenOfType().Count() == 2); AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); - AddRepeatStep("remove the remaining two users", () => SelectedRoom.Value.RecentParticipants.RemoveAt(0), 2); + AddRepeatStep("remove the remaining two users", () => removeUserAt(0), 2); AddAssert("0 avatars displayed", () => !list.ChildrenOfType().Any()); } + + private void addUser(int id) + { + SelectedRoom.Value.ParticipantCount.Value++; + SelectedRoom.Value.RecentParticipants.Add(new User + { + Id = id, + Username = $"User {id}" + }); + } + + private void removeUserAt(int index) + { + SelectedRoom.Value.ParticipantCount.Value--; + SelectedRoom.Value.RecentParticipants.RemoveAt(index); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index bbea1ea1c3..da410716e4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -88,6 +88,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components base.LoadComplete(); RecentParticipants.BindCollectionChanged(onParticipantsChanged, true); + ParticipantCount.BindValueChanged(_ => updateHiddenUserCount(), true); } private int numberOfAvatars = 3; @@ -141,8 +142,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { if (avatarFlow.Count < NumberOfAvatars) avatarFlow.Add(new CircularAvatar { User = user }); - else - hiddenUsers.Count++; + + updateHiddenUserCount(); } private void removeUser(User user) @@ -150,21 +151,20 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components if (avatarFlow.RemoveAll(a => a.User == user) > 0) { if (RecentParticipants.Count >= NumberOfAvatars) - { avatarFlow.Add(new CircularAvatar { User = RecentParticipants.First(u => avatarFlow.All(a => a.User != u)) }); - hiddenUsers.Count--; - } } - else - hiddenUsers.Count--; + + updateHiddenUserCount(); } private void clearUsers() { avatarFlow.Clear(); - hiddenUsers.Count = 0; + updateHiddenUserCount(); } + private void updateHiddenUserCount() => hiddenUsers.Count = ParticipantCount.Value - avatarFlow.Count; + private class CircularAvatar : CompositeDrawable { public User User From 74bffeac5e0419bdc2d50164ed9420f0e723f167 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 17:03:44 +0900 Subject: [PATCH 068/961] Minor design adustments (paddings/sizing) --- .../Lounge/Components/DrawableRoom.cs | 2 +- .../Lounge/Components/PillContainer.cs | 25 +++++++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index ee0e1b5adc..e973dc75a7 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -288,7 +288,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Scale = new Vector2(0.85f) + Scale = new Vector2(0.8f) } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs index ca153f7e9a..109851a16b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/PillContainer.cs @@ -17,12 +17,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public readonly Drawable Background; - protected override Container Content { get; } = new Container - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - AutoSizeAxes = Axes.Both, - }; + protected override Container Content => content; + private readonly Container content; public PillContainer() { @@ -59,7 +55,22 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Content = new[] { - new[] { Content } + new[] + { + new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Padding = new MarginPadding { Bottom = 2 }, + Child = content = new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + } } } } From bdfdd00afed0be62426123033f828de0be0ed590 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 18:52:01 +0900 Subject: [PATCH 069/961] Adjust spacings and sizings of left-side details --- .../Multiplayer/TestSceneDrawableRoom.cs | 2 +- .../Lounge/Components/DrawableRoom.cs | 71 ++++++++++--------- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index adada5890e..e6a1bbeb92 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { createDrawableRoom(new Room { - Name = { Value = "Room 1" }, + Name = { Value = "Flyte's Trash Playlist" }, Status = { Value = new RoomStatusOpen() }, EndDate = { Value = DateTimeOffset.Now.AddDays(1) }, Playlist = diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index e973dc75a7..179aef6a9b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -236,39 +236,46 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { new FillFlowContainer { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new RoomStatusPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - specialCategoryPill = new RoomSpecialCategoryPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - new EndDateInfo - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - } - }, - new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Children = new Drawable[] { - new RoomNameText(), - new RoomHostText() - } + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new RoomStatusPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + specialCategoryPill = new RoomSpecialCategoryPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + new EndDateInfo + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 3 }, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new RoomNameText(), + new RoomHostText(), + } + } + }, }, new FillFlowContainer { @@ -276,7 +283,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Origin = Anchor.BottomLeft, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(4), + Spacing = new Vector2(5), Children = new Drawable[] { new PlaylistCountPill @@ -429,7 +436,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public RoomNameText() { - Font = OsuFont.GetFont(size: 24); + Font = OsuFont.GetFont(size: 28); } [BackgroundDependencyLoader] @@ -451,7 +458,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [BackgroundDependencyLoader] private void load() { - InternalChild = hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14)) + InternalChild = hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 16)) { AutoSizeAxes = Axes.Both }; From 798b16fc245b83ae8f1165ba442a3e948bbac31a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 18:52:46 +0900 Subject: [PATCH 070/961] Remove unused params --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 179aef6a9b..6ab46d5527 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -163,7 +163,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Colour = background_colour, }, - new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) + new OnlinePlayBackgroundSprite { RelativeSizeAxes = Axes.Both }, @@ -193,7 +193,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Colour = background_colour, }, - new OnlinePlayBackgroundSprite(BeatmapSetCoverType.Cover) + new OnlinePlayBackgroundSprite { RelativeSizeAxes = Axes.Both }, From 9019e0947a31c2fd3b0f28b81f68a2520343e2b3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 18:54:02 +0900 Subject: [PATCH 071/961] Remove unused using --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 6ab46d5527..440c23b8fd 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -19,7 +19,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; From 19ed24a06f47a03e2443cea8291616a820068c1a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 18:59:19 +0900 Subject: [PATCH 072/961] Remove unnecessary duplicate background --- .../Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 440c23b8fd..53af2fe5c7 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -187,15 +187,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = background_colour, - }, - new OnlinePlayBackgroundSprite - { - RelativeSizeAxes = Axes.Both - }, new GridContainer { RelativeSizeAxes = Axes.Both, From c680012523ff9f4a1e8ab10f788401a9f3b68986 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 19:06:16 +0900 Subject: [PATCH 073/961] Buffer the entire star rating range to fix overlapping alpha --- .../Components/StarRatingRangeDisplay.cs | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 3b4ac69466..efc93ffeb0 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -33,38 +33,41 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - InternalChildren = new Drawable[] + InternalChild = new BufferedContainer { - new Container + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 1, - Children = new[] + new Container { - minBackground = new Box + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Vertical = 1 }, + Children = new[] { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f), - }, - maxBackground = new Box - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f), - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] + minBackground = new Box + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + }, + maxBackground = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + }, + } + }, + new FillFlowContainer { - minDisplay = new StarRatingDisplay(default), - maxDisplay = new StarRatingDisplay(default) + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + minDisplay = new StarRatingDisplay(default), + maxDisplay = new StarRatingDisplay(default) + } } } }; From 52400961f6ee5974c1bb0205005954a597ed2e99 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 6 Aug 2021 20:59:26 +0900 Subject: [PATCH 074/961] Add open/close sounds to context menus --- .../UserInterface/TestSceneContextMenu.cs | 61 ++++++++++++++++--- .../Cursor/OsuContextMenuContainer.cs | 2 +- .../Graphics/UserInterface/OsuContextMenu.cs | 53 ++++++++++++++-- 3 files changed, 100 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs index 53693d1b70..3b43f8485a 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneContextMenu.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.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -68,13 +70,40 @@ namespace osu.Game.Tests.Visual.UserInterface ); } - private class MyContextMenuContainer : Container, IHasContextMenu + private static MenuItem[] makeMenu() { - public MenuItem[] ContextMenuItems => new MenuItem[] + return new MenuItem[] { new OsuMenuItem(@"Some option"), new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted), new OsuMenuItem(@"Another option"), + new OsuMenuItem(@"Nested option >") + { + Items = new MenuItem[] + { + new OsuMenuItem(@"Sub-One"), + new OsuMenuItem(@"Sub-Two"), + new OsuMenuItem(@"Sub-Three"), + new OsuMenuItem(@"Sub-Nested option >") + { + Items = new MenuItem[] + { + new OsuMenuItem(@"Double Sub-One"), + new OsuMenuItem(@"Double Sub-Two"), + new OsuMenuItem(@"Double Sub-Three"), + new OsuMenuItem(@"Sub-Sub-Nested option >") + { + Items = new MenuItem[] + { + new OsuMenuItem(@"Too Deep One"), + new OsuMenuItem(@"Too Deep Two"), + new OsuMenuItem(@"Too Deep Three"), + } + } + } + } + } + }, new OsuMenuItem(@"Choose me please"), new OsuMenuItem(@"And me too"), new OsuMenuItem(@"Trying to fill"), @@ -82,17 +111,29 @@ namespace osu.Game.Tests.Visual.UserInterface }; } + private class MyContextMenuContainer : Container, IHasContextMenu + { + public MenuItem[] ContextMenuItems => makeMenu(); + } + private class AnotherContextMenuContainer : Container, IHasContextMenu { - public MenuItem[] ContextMenuItems => new MenuItem[] + public MenuItem[] ContextMenuItems { - new OsuMenuItem(@"Simple option"), - new OsuMenuItem(@"Simple very very long option"), - new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)), - new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)), - new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)), - new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)), - }; + get + { + List items = makeMenu().ToList(); + items.AddRange(new MenuItem[] + { + new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)), + new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)), + new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)), + new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)), + }); + + return items.ToArray(); + } + } } } } diff --git a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs index fbb3fa0e6c..e64d2d98f4 100644 --- a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs @@ -9,6 +9,6 @@ namespace osu.Game.Graphics.Cursor { public class OsuContextMenuContainer : ContextMenuContainer { - protected override Menu CreateMenu() => new OsuContextMenu(); + protected override Menu CreateMenu() => new OsuContextMenu(true); } } diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index 8c7b44f952..7cf8b3eca8 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -3,6 +3,9 @@ using osuTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; @@ -13,8 +16,16 @@ namespace osu.Game.Graphics.UserInterface public class OsuContextMenu : OsuMenu { private const int fade_duration = 250; + private Sample sampleOpen; + private Sample sampleClose; + private Sample sampleClick; - public OsuContextMenu() + // todo: this shouldn't be required after https://github.com/ppy/osu-framework/issues/4519 is fixed. + private bool wasOpened; + private readonly bool playClickSample; + private readonly Menu parentMenu; + + public OsuContextMenu(bool playClickSample = false, Menu parentMenu = null) : base(Direction.Vertical) { MaskingContainer.CornerRadius = 5; @@ -28,17 +39,49 @@ namespace osu.Game.Graphics.UserInterface ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL }; MaxHeight = 250; + + this.playClickSample = playClickSample; + this.parentMenu = parentMenu; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, AudioManager audio) { BackgroundColour = colours.ContextMenuGray; + sampleClick = audio.Samples.Get($"UI/{HoverSampleSet.Default.GetDescription()}-select"); + sampleOpen = audio.Samples.Get(@"UI/dropdown-open"); + sampleClose = audio.Samples.Get(@"UI/dropdown-close"); } - protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); - protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); + protected override void AnimateOpen() + { + this.FadeIn(fade_duration, Easing.OutQuint); - protected override Menu CreateSubMenu() => new OsuContextMenu(); + if (playClickSample) + sampleClick?.Play(); + + if (!wasOpened) + sampleOpen?.Play(); + + wasOpened = true; + } + + protected override void AnimateClose() + { + this.FadeOut(fade_duration, Easing.OutQuint); + + if (parentMenu?.State == MenuState.Closed) + { + wasOpened = false; + return; + } + + if (wasOpened) + sampleClose?.Play(); + + wasOpened = false; + } + + protected override Menu CreateSubMenu() => new OsuContextMenu(false, this); } } From 067ff0e0ad4051ceaa7a8726d8f38d3ce884a8d6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Aug 2021 18:38:14 +0300 Subject: [PATCH 075/961] Store last opened settings subpanel rather than relying on LINQ --- osu.Game/Overlays/SettingsOverlay.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 54b780615d..050502b3be 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -9,7 +9,6 @@ using osu.Game.Overlays.Settings.Sections; using osu.Game.Overlays.Settings.Sections.Input; using osuTK.Graphics; using System.Collections.Generic; -using System.Linq; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Game.Localisation; @@ -38,6 +37,8 @@ namespace osu.Game.Overlays private readonly List subPanels = new List(); + private SettingsSubPanel lastOpenedSubPanel; + protected override Drawable CreateHeader() => new SettingsHeader(Title, Description); protected override Drawable CreateFooter() => new SettingsFooter(); @@ -46,21 +47,21 @@ namespace osu.Game.Overlays { } - public override bool AcceptsFocus => subPanels.All(s => s.State.Value != Visibility.Visible); + public override bool AcceptsFocus => lastOpenedSubPanel == null || lastOpenedSubPanel.State.Value == Visibility.Hidden; private T createSubPanel(T subPanel) where T : SettingsSubPanel { subPanel.Depth = 1; subPanel.Anchor = Anchor.TopRight; - subPanel.State.ValueChanged += subPanelStateChanged; + subPanel.State.ValueChanged += e => subPanelStateChanged(subPanel, e); subPanels.Add(subPanel); return subPanel; } - private void subPanelStateChanged(ValueChangedEvent state) + private void subPanelStateChanged(SettingsSubPanel panel, ValueChangedEvent state) { switch (state.NewValue) { @@ -69,6 +70,8 @@ namespace osu.Game.Overlays SectionsContainer.FadeOut(300, Easing.OutQuint); ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint); + + lastOpenedSubPanel = panel; break; case Visibility.Hidden: @@ -80,7 +83,7 @@ namespace osu.Game.Overlays } } - protected override float ExpandedPosition => subPanels.Any(s => s.State.Value == Visibility.Visible) ? -WIDTH : base.ExpandedPosition; + protected override float ExpandedPosition => lastOpenedSubPanel?.State.Value == Visibility.Visible ? -WIDTH : base.ExpandedPosition; [BackgroundDependencyLoader] private void load() From 8e8e0fb8d8c9abce26fe64a0098507c8967d0739 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Aug 2021 18:36:43 +0300 Subject: [PATCH 076/961] Add placement-dependent horizontal screen offset properties --- osu.Game/Overlays/NotificationOverlay.cs | 5 +++++ osu.Game/Overlays/SettingsOverlay.cs | 2 ++ osu.Game/Overlays/SettingsPanel.cs | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index b26e17b34c..af4f41901f 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -30,6 +30,11 @@ namespace osu.Game.Overlays private FlowContainer sections; + /// + /// A horizontal offset to apply to the game-wide screen. + /// + public float HorizontalScreenOffset => -width + X; + /// /// Provide a source for the toolbar height. /// diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 050502b3be..9ed1d950e3 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -21,6 +21,8 @@ namespace osu.Game.Overlays public LocalisableString Title => SettingsStrings.HeaderTitle; public LocalisableString Description => SettingsStrings.HeaderDescription; + public override float HorizontalScreenOffset => base.HorizontalScreenOffset + (lastOpenedSubPanel?.HorizontalScreenOffset ?? 0f); + protected override IEnumerable CreateSections() => new SettingsSection[] { new GeneralSection(), diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index eae828c142..2916ea013f 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -34,6 +34,11 @@ namespace osu.Game.Overlays protected override Container Content => ContentContainer; + /// + /// A horizontal offset to apply to the game-wide screen. + /// + public virtual float HorizontalScreenOffset => (WIDTH + Content?.X) ?? 0f; + protected Sidebar Sidebar; private SidebarButton selectedSidebarButton; @@ -64,6 +69,7 @@ namespace osu.Game.Overlays { InternalChild = ContentContainer = new NonMaskedContent { + X = -WIDTH + ExpandedPosition, Width = WIDTH, RelativeSizeAxes = Axes.Y, Children = new Drawable[] From f77037ef57d6df00845867ae436ceb77e3f525dd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Aug 2021 18:38:48 +0300 Subject: [PATCH 077/961] Replace state-based screen offsetting logic with `HorizontalScreenOffset`s --- osu.Game/OsuGame.cs | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 3cfa2cc755..85428a12e3 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -828,21 +828,6 @@ namespace osu.Game { if (mode.NewValue != OverlayActivation.All) CloseAllOverlays(); }; - - void updateScreenOffset() - { - float offset = 0; - - if (Settings.State.Value == Visibility.Visible) - offset += Toolbar.HEIGHT / 2; - if (notifications.State.Value == Visibility.Visible) - offset -= Toolbar.HEIGHT / 2; - - screenOffsetContainer.MoveToX(offset, SettingsPanel.TRANSITION_LENGTH, Easing.OutQuint); - } - - Settings.State.ValueChanged += _ => updateScreenOffset(); - notifications.State.ValueChanged += _ => updateScreenOffset(); } private void showOverlayAboveOthers(OverlayContainer overlay, OverlayContainer[] otherOverlays) @@ -1026,6 +1011,9 @@ namespace osu.Game screenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; + screenOffsetContainer.X = Settings.HorizontalScreenOffset * 0.125f + + notifications.HorizontalScreenOffset * 0.125f; + MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; } From ac157f6cef91f35252599059451fa315819180cf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Aug 2021 22:10:03 +0300 Subject: [PATCH 078/961] Fix settings panel children not processing transforms while masked away --- osu.Game/Overlays/SettingsPanel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 2916ea013f..79d78e6805 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -34,6 +34,12 @@ namespace osu.Game.Overlays protected override Container Content => ContentContainer; + /// + /// The always needs to be present for to process transforms while overlay is masked away. + /// todo: there may be a better solution for this and the existing , likely requires a refactor. + /// + public override bool IsPresent => true; + /// /// A horizontal offset to apply to the game-wide screen. /// From 8dc0650ca71d9143d0268268a6f21f826d658679 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 6 Aug 2021 22:36:40 +0300 Subject: [PATCH 079/961] Add test coverage --- .../Visual/Menus/TestSceneSideOverlays.cs | 62 +++++++++++++++++++ .../Visual/Navigation/OsuGameTestScene.cs | 7 ++- osu.Game/OsuGame.cs | 33 +++++----- osu.Game/Overlays/NotificationOverlay.cs | 8 +-- 4 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs new file mode 100644 index 0000000000..34259574f3 --- /dev/null +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -0,0 +1,62 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Overlays.Settings.Sections.Input; +using osu.Game.Tests.Visual.Navigation; + +namespace osu.Game.Tests.Visual.Menus +{ + public class TestSceneSideOverlays : OsuGameTestScene + { + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddAssert("no screen offset applied", () => Game.ScreenOffsetContainer.X == 0f); + } + + [Test] + public void TestScreenOffsettingOnSettingsOverlay() + { + AddStep("open settings", () => Game.Settings.Show()); + AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + + AddStep("hide settings", () => Game.Settings.Hide()); + AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + } + + [Test] + public void TestScreenOffsettingAccountsForKeyBindingPanel() + { + AddStep("open settings", () => Game.Settings.Show()); + AddStep("open key binding panel", () => Game.Settings.ChildrenOfType().Single().Show()); + AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + + AddStep("hide key binding", () => Game.Settings.ChildrenOfType().Single().Show()); + AddUntilStep("right screen offset still applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + + AddStep("open key binding", () => Game.Settings.Show()); + AddUntilStep("right screen offset still applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + + AddStep("hide settings", () => Game.Settings.Hide()); + AddAssert("key binding panel still open", () => Game.Settings.ChildrenOfType().Single().State.Value == Visibility.Visible); + AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + } + + [Test] + public void TestScreenOffsettingOnNotificationOverlay() + { + AddStep("open notifications", () => Game.Notifications.Show()); + AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + + AddStep("hide notifications", () => Game.Notifications.Hide()); + AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + } + } +} diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs index f9a991f756..5cd55ed233 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs @@ -6,6 +6,7 @@ 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.Shapes; using osu.Framework.Platform; using osu.Framework.Screens; @@ -103,7 +104,11 @@ namespace osu.Game.Tests.Visual.Navigation public new ScoreManager ScoreManager => base.ScoreManager; - public new SettingsPanel Settings => base.Settings; + public new Container ScreenOffsetContainer => base.ScreenOffsetContainer; + + public new SettingsOverlay Settings => base.Settings; + + public new NotificationOverlay Notifications => base.Notifications; public new MusicController MusicController => base.MusicController; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 85428a12e3..d2f86f812e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -64,6 +64,8 @@ namespace osu.Game /// public class OsuGame : OsuGameBase, IKeyBindingHandler { + public const float SCREEN_OFFSET_RATIO = 0.125f; + public Toolbar Toolbar; private ChatOverlay chatOverlay; @@ -71,7 +73,7 @@ namespace osu.Game private ChannelManager channelManager; [NotNull] - private readonly NotificationOverlay notifications = new NotificationOverlay(); + protected readonly NotificationOverlay Notifications = new NotificationOverlay(); private BeatmapListingOverlay beatmapListing; @@ -97,7 +99,7 @@ namespace osu.Game private ScalingContainer screenContainer; - private Container screenOffsetContainer; + protected Container ScreenOffsetContainer; [Resolved] private FrameworkConfigManager frameworkConfig { get; set; } @@ -312,7 +314,7 @@ namespace osu.Game case LinkAction.OpenEditorTimestamp: case LinkAction.JoinMultiplayerMatch: case LinkAction.Spectate: - waitForReady(() => notifications, _ => notifications.Post(new SimpleNotification + waitForReady(() => Notifications, _ => Notifications.Post(new SimpleNotification { Text = @"This link type is not yet supported!", Icon = FontAwesome.Solid.LifeRing, @@ -611,12 +613,12 @@ namespace osu.Game MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false; // todo: all archive managers should be able to be looped here. - SkinManager.PostNotification = n => notifications.Post(n); + SkinManager.PostNotification = n => Notifications.Post(n); - BeatmapManager.PostNotification = n => notifications.Post(n); + BeatmapManager.PostNotification = n => Notifications.Post(n); BeatmapManager.PresentImport = items => PresentBeatmap(items.First()); - ScoreManager.PostNotification = n => notifications.Post(n); + ScoreManager.PostNotification = n => Notifications.Post(n); ScoreManager.PresentImport = items => PresentScore(items.First()); // make config aware of how to lookup skins for on-screen display purposes. @@ -655,7 +657,7 @@ namespace osu.Game ActionRequested = action => volume.Adjust(action), ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise), }, - screenOffsetContainer = new Container + ScreenOffsetContainer = new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] @@ -724,7 +726,7 @@ namespace osu.Game loadComponentSingleFile(onScreenDisplay, Add, true); - loadComponentSingleFile(notifications.With(d => + loadComponentSingleFile(Notifications.With(d => { d.GetToolbarHeight = () => ToolbarOffset; d.Anchor = Anchor.TopRight; @@ -733,7 +735,7 @@ namespace osu.Game loadComponentSingleFile(new CollectionManager(Storage) { - PostNotification = n => notifications.Post(n), + PostNotification = n => Notifications.Post(n), }, Add, true); loadComponentSingleFile(stableImportManager, Add); @@ -785,7 +787,7 @@ namespace osu.Game Add(new MusicKeyBindingHandler()); // side overlays which cancel each other. - var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications }; + var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications }; foreach (var overlay in singleDisplaySideOverlays) { @@ -859,7 +861,7 @@ namespace osu.Game if (recentLogCount < short_term_display_limit) { - Schedule(() => notifications.Post(new SimpleErrorNotification + Schedule(() => Notifications.Post(new SimpleErrorNotification { Icon = entry.Level == LogLevel.Important ? FontAwesome.Solid.ExclamationCircle : FontAwesome.Solid.Bomb, Text = entry.Message.Truncate(256) + (entry.Exception != null && IsDeployedBuild ? "\n\nThis error has been automatically reported to the devs." : string.Empty), @@ -867,7 +869,7 @@ namespace osu.Game } else if (recentLogCount == short_term_display_limit) { - Schedule(() => notifications.Post(new SimpleNotification + Schedule(() => Notifications.Post(new SimpleNotification { Icon = FontAwesome.Solid.EllipsisH, Text = "Subsequent messages have been logged. Click to view log files.", @@ -1008,11 +1010,12 @@ namespace osu.Game { base.UpdateAfterChildren(); - screenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; + ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; - screenOffsetContainer.X = Settings.HorizontalScreenOffset * 0.125f + - notifications.HorizontalScreenOffset * 0.125f; + var settingsOffset = Settings.HorizontalScreenOffset * SCREEN_OFFSET_RATIO; + var notificationsOffset = Notifications.HorizontalScreenOffset * SCREEN_OFFSET_RATIO; + ScreenOffsetContainer.X = settingsOffset + notificationsOffset; MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index af4f41901f..9be3212159 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays public LocalisableString Title => NotificationsStrings.HeaderTitle; public LocalisableString Description => NotificationsStrings.HeaderDescription; - private const float width = 320; + public const float WIDTH = 320; public const float TRANSITION_LENGTH = 600; @@ -33,7 +33,7 @@ namespace osu.Game.Overlays /// /// A horizontal offset to apply to the game-wide screen. /// - public float HorizontalScreenOffset => -width + X; + public float HorizontalScreenOffset => -WIDTH + X; /// /// Provide a source for the toolbar height. @@ -43,7 +43,7 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { - Width = width; + Width = WIDTH; RelativeSizeAxes = Axes.Y; Children = new Drawable[] @@ -157,7 +157,7 @@ namespace osu.Game.Overlays markAllRead(); - this.MoveToX(width, TRANSITION_LENGTH, Easing.OutQuint); + this.MoveToX(WIDTH, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } From 7bbc917f75dba460e055c8eb2981f8808967c9a5 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 6 Aug 2021 22:50:57 +0200 Subject: [PATCH 080/961] Localise beatmap picker. --- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 66886b0882..b16fb76ec3 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -11,11 +11,13 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; using osuTK; @@ -26,7 +28,8 @@ namespace osu.Game.Overlays.BeatmapSet private const float tile_icon_padding = 7; private const float tile_spacing = 2; - private readonly OsuSpriteText version, starRating; + private readonly OsuSpriteText version, starRating, starRatingText; + private readonly FillFlowContainer starRatingContainer; private readonly Statistic plays, favourites; public readonly DifficultiesContainer Difficulties; @@ -68,14 +71,14 @@ namespace osu.Game.Overlays.BeatmapSet OnLostHover = () => { showBeatmap(Beatmap.Value); - starRating.FadeOut(100); + starRatingContainer.FadeOut(100); }, }, new FillFlowContainer { AutoSizeAxes = Axes.Both, Spacing = new Vector2(5f), - Children = new[] + Children = new Drawable[] { version = new OsuSpriteText { @@ -83,14 +86,31 @@ namespace osu.Game.Overlays.BeatmapSet Origin = Anchor.BottomLeft, Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold) }, - starRating = new OsuSpriteText + starRatingContainer = new FillFlowContainer { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, - Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold), - Text = "Star Difficulty", Alpha = 0, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(2f, 0), Margin = new MarginPadding { Bottom = 1 }, + Children = new[] + { + starRatingText = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold), + Text = BeatmapsetsStrings.ShowStatsStars, + }, + starRating = new OsuSpriteText + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Font = OsuFont.GetFont(size: 11, weight: FontWeight.Bold), + Text = string.Empty, + }, + } }, }, }, @@ -124,6 +144,7 @@ namespace osu.Game.Overlays.BeatmapSet private void load(OsuColour colours) { starRating.Colour = colours.Yellow; + starRatingText.Colour = colours.Yellow; updateDisplay(); } @@ -149,14 +170,14 @@ namespace osu.Game.Overlays.BeatmapSet OnHovered = beatmap => { showBeatmap(beatmap); - starRating.Text = beatmap.StarDifficulty.ToString("Star Difficulty 0.##"); - starRating.FadeIn(100); + starRating.Text = beatmap.StarDifficulty.ToLocalisableString(@"0.##"); + starRatingContainer.FadeIn(100); }, OnClicked = beatmap => { Beatmap.Value = beatmap; }, }); } - starRating.FadeOut(100); + starRatingContainer.FadeOut(100); Beatmap.Value = Difficulties.FirstOrDefault()?.Beatmap; plays.Value = BeatmapSet?.OnlineInfo.PlayCount ?? 0; favourites.Value = BeatmapSet?.OnlineInfo.FavouriteCount ?? 0; @@ -300,7 +321,7 @@ namespace osu.Game.Overlays.BeatmapSet set { this.value = value; - text.Text = Value.ToString(@"N0"); + text.Text = Value.ToLocalisableString(@"N0"); } } From ae733e202ff574b9a3065b9bc72fca71b8960580 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 00:36:52 +0300 Subject: [PATCH 081/961] Fix tests executing before overlays load --- osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index 34259574f3..598998586d 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -19,6 +19,7 @@ namespace osu.Game.Tests.Visual.Menus base.SetUpSteps(); AddAssert("no screen offset applied", () => Game.ScreenOffsetContainer.X == 0f); + AddUntilStep("wait for overlays", () => Game.Settings.IsLoaded && Game.Notifications.IsLoaded); } [Test] From 9ac5c9aa2f8d426d1733140702ab3d3c518bce99 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 01:27:54 +0300 Subject: [PATCH 082/961] Fix notification overlay having incorrect initial X --- osu.Game/Overlays/NotificationOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 9be3212159..cb5d4d57c6 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -43,6 +43,7 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load() { + X = WIDTH; Width = WIDTH; RelativeSizeAxes = Axes.Y; From e924ea8d934d043a446d92a0ffeea7885cee46ec Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 18:52:27 +0300 Subject: [PATCH 083/961] Make `ScreenOffsetContainer` privatly settable only --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index d2f86f812e..6fb884f80a 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -99,7 +99,7 @@ namespace osu.Game private ScalingContainer screenContainer; - protected Container ScreenOffsetContainer; + protected Container ScreenOffsetContainer { get; private set; } [Resolved] private FrameworkConfigManager frameworkConfig { get; set; } From fc48696718796a1cb3597e9132e362c8ec187ff5 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sat, 7 Aug 2021 18:27:55 +0200 Subject: [PATCH 084/961] Localise detail buttons. --- .../Localisation/DownloadButtonStrings.cs | 24 +++++++++++++++++++ .../BeatmapSet/Buttons/FavouriteButton.cs | 3 ++- .../Buttons/HeaderDownloadButton.cs | 14 ++++++----- 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Localisation/DownloadButtonStrings.cs diff --git a/osu.Game/Localisation/DownloadButtonStrings.cs b/osu.Game/Localisation/DownloadButtonStrings.cs new file mode 100644 index 0000000000..736f309624 --- /dev/null +++ b/osu.Game/Localisation/DownloadButtonStrings.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class DownloadButtonStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.DownloadButton"; + + /// + /// "Downloading..." + /// + public static LocalisableString Downloading => new TranslatableString(getKey(@"downloading"), @"Downloading..."); + + /// + /// "Importing..." + /// + public static LocalisableString Importing => new TranslatableString(getKey(@"importing"), @"Importing..."); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index bb87e7151b..43dd1438f1 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Overlays.Notifications; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users; using osuTK; @@ -35,7 +36,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { if (!Enabled.Value) return string.Empty; - return (favourited.Value ? "Unfavourite" : "Favourite") + " this beatmapset"; + return favourited.Value ? BeatmapsetsStrings.ShowDetailsUnfavourite : BeatmapsetsStrings.ShowDetailsFavourite; } } diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index cef623e59b..441ef2f6cf 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -15,9 +15,11 @@ using osu.Game.Graphics.Sprites; using osu.Game.Online; using osu.Game.Online.API; using osu.Game.Overlays.BeatmapListing.Panels; +using osu.Game.Resources.Localisation.Web; using osu.Game.Users; using osuTK; using osuTK.Graphics; +using osu.Game.Localisation; namespace osu.Game.Overlays.BeatmapSet.Buttons { @@ -27,7 +29,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private readonly bool noVideo; - public LocalisableString TooltipText => button.Enabled.Value ? "download this beatmap" : "login to download"; + public LocalisableString TooltipText => button.Enabled.Value ? BeatmapsetsStrings.ShowDetailsDownloadDefault : BeatmapsetsStrings.ShowDetailsLoggedOut; private readonly IBindable localUser = new Bindable(); @@ -113,7 +115,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = "Downloading...", + Text = DownloadButtonStrings.Downloading, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, }; @@ -124,7 +126,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = "Importing...", + Text = DownloadButtonStrings.Importing, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, }; @@ -139,7 +141,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = "Download", + Text = BeatmapsetsStrings.ShowDetailsDownloadDefault, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, new OsuSpriteText @@ -158,12 +160,12 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private void enabledChanged(ValueChangedEvent e) => this.FadeColour(e.NewValue ? Color4.White : Color4.Gray, 200, Easing.OutQuint); - private string getVideoSuffixText() + private LocalisableString getVideoSuffixText() { if (!BeatmapSet.Value.OnlineInfo.HasVideo) return string.Empty; - return noVideo ? "without Video" : "with Video"; + return noVideo ? BeatmapsetsStrings.ShowDetailsDownloadNoVideo : BeatmapsetsStrings.ShowDetailsDownloadVideo; } } } From 9f3013e2c89a1ea018008cb6221d9165e72f13a2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 19:30:12 +0300 Subject: [PATCH 085/961] Remove all `HorizontalScreenOffset` calculations from overlays --- osu.Game/Overlays/NotificationOverlay.cs | 5 ----- osu.Game/Overlays/SettingsOverlay.cs | 2 -- osu.Game/Overlays/SettingsPanel.cs | 5 ----- 3 files changed, 12 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index cb5d4d57c6..e3956089c2 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -30,11 +30,6 @@ namespace osu.Game.Overlays private FlowContainer sections; - /// - /// A horizontal offset to apply to the game-wide screen. - /// - public float HorizontalScreenOffset => -WIDTH + X; - /// /// Provide a source for the toolbar height. /// diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 9ed1d950e3..050502b3be 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -21,8 +21,6 @@ namespace osu.Game.Overlays public LocalisableString Title => SettingsStrings.HeaderTitle; public LocalisableString Description => SettingsStrings.HeaderDescription; - public override float HorizontalScreenOffset => base.HorizontalScreenOffset + (lastOpenedSubPanel?.HorizontalScreenOffset ?? 0f); - protected override IEnumerable CreateSections() => new SettingsSection[] { new GeneralSection(), diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 79d78e6805..64c3be4b9a 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -40,11 +40,6 @@ namespace osu.Game.Overlays /// public override bool IsPresent => true; - /// - /// A horizontal offset to apply to the game-wide screen. - /// - public virtual float HorizontalScreenOffset => (WIDTH + Content?.X) ?? 0f; - protected Sidebar Sidebar; private SidebarButton selectedSidebarButton; From 19a19f915cde29015df6e085406af348c487bba4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 19:56:51 +0300 Subject: [PATCH 086/961] Adjust settings panel to autosize to zero when hiding it Previously, when hiding the settings overlay, it remains to have a width of `56` (sidebar width), this is due to the panel content being placed next to the sidebar, so therefore the content has to move 400 (PANEL_WIDTH) + 56 (sidebar_width) backwards, for the overlay to have a width of 0 on hide. --- .../Visual/Settings/TestSceneTabletSettings.cs | 2 +- osu.Game/Overlays/SettingsOverlay.cs | 4 ++-- osu.Game/Overlays/SettingsPanel.cs | 12 ++++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index a62980addf..da474a64ba 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Settings new TabletSettings(tabletHandler) { RelativeSizeAxes = Axes.None, - Width = SettingsPanel.WIDTH, + Width = SettingsPanel.PANEL_WIDTH, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, } diff --git a/osu.Game/Overlays/SettingsOverlay.cs b/osu.Game/Overlays/SettingsOverlay.cs index 050502b3be..55e8aee266 100644 --- a/osu.Game/Overlays/SettingsOverlay.cs +++ b/osu.Game/Overlays/SettingsOverlay.cs @@ -69,7 +69,7 @@ namespace osu.Game.Overlays Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint); SectionsContainer.FadeOut(300, Easing.OutQuint); - ContentContainer.MoveToX(-WIDTH, 500, Easing.OutQuint); + ContentContainer.MoveToX(-PANEL_WIDTH, 500, Easing.OutQuint); lastOpenedSubPanel = panel; break; @@ -83,7 +83,7 @@ namespace osu.Game.Overlays } } - protected override float ExpandedPosition => lastOpenedSubPanel?.State.Value == Visibility.Visible ? -WIDTH : base.ExpandedPosition; + protected override float ExpandedPosition => lastOpenedSubPanel?.State.Value == Visibility.Visible ? -PANEL_WIDTH : base.ExpandedPosition; [BackgroundDependencyLoader] private void load() diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 64c3be4b9a..8b953e8655 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -28,7 +28,15 @@ namespace osu.Game.Overlays private const float sidebar_width = Sidebar.DEFAULT_WIDTH; - public const float WIDTH = 400; + /// + /// The width of the settings panel content, excluding the sidebar. + /// + public const float PANEL_WIDTH = 400; + + /// + /// The full width of the settings panel, including the sidebar. + /// + public const float WIDTH = sidebar_width + PANEL_WIDTH; protected Container ContentContainer; @@ -71,7 +79,7 @@ namespace osu.Game.Overlays InternalChild = ContentContainer = new NonMaskedContent { X = -WIDTH + ExpandedPosition, - Width = WIDTH, + Width = PANEL_WIDTH, RelativeSizeAxes = Axes.Y, Children = new Drawable[] { From d099bb8ab631424f6a841d4f9947dc1ca3ba45bf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 7 Aug 2021 19:33:22 +0300 Subject: [PATCH 087/961] Calculate offsets from overlay `ScreenSpaceDrawQuad`s instead --- .../Visual/Menus/TestSceneSideOverlays.cs | 21 ------------------- osu.Game/OsuGame.cs | 7 ++++--- 2 files changed, 4 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index 598998586d..21db7e2802 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -1,12 +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.Linq; using NUnit.Framework; -using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Overlays; -using osu.Game.Overlays.Settings.Sections.Input; using osu.Game.Tests.Visual.Navigation; namespace osu.Game.Tests.Visual.Menus @@ -32,24 +29,6 @@ namespace osu.Game.Tests.Visual.Menus AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); } - [Test] - public void TestScreenOffsettingAccountsForKeyBindingPanel() - { - AddStep("open settings", () => Game.Settings.Show()); - AddStep("open key binding panel", () => Game.Settings.ChildrenOfType().Single().Show()); - AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); - - AddStep("hide key binding", () => Game.Settings.ChildrenOfType().Single().Show()); - AddUntilStep("right screen offset still applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); - - AddStep("open key binding", () => Game.Settings.Show()); - AddUntilStep("right screen offset still applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); - - AddStep("hide settings", () => Game.Settings.Hide()); - AddAssert("key binding panel still open", () => Game.Settings.ChildrenOfType().Single().State.Value == Visibility.Visible); - AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); - } - [Test] public void TestScreenOffsettingOnNotificationOverlay() { diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6fb884f80a..1539d984ae 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1013,9 +1013,10 @@ namespace osu.Game ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; - var settingsOffset = Settings.HorizontalScreenOffset * SCREEN_OFFSET_RATIO; - var notificationsOffset = Notifications.HorizontalScreenOffset * SCREEN_OFFSET_RATIO; - ScreenOffsetContainer.X = settingsOffset + notificationsOffset; + ScreenOffsetContainer.X = 0f; + + if (Settings.IsLoaded) ScreenOffsetContainer.X += (ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X) * SCREEN_OFFSET_RATIO; + if (Notifications.IsLoaded) ScreenOffsetContainer.X += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; } From 3a0dd5b019e2401f917d2656ae73ef9ddd09847b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 8 Aug 2021 01:37:45 +0300 Subject: [PATCH 088/961] Add more insane star difficulties for visual testing --- .../Visual/UserInterface/TestSceneStarRatingDisplay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 2f3593c062..a8bc5664f3 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; +using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Tests.Visual.UserInterface @@ -28,19 +29,19 @@ namespace osu.Game.Tests.Visual.UserInterface AutoSizeAxes = Axes.Both, Spacing = new Vector2(2f), Direction = FillDirection.Horizontal, - ChildrenEnumerable = Enumerable.Range(0, 10).Select(i => new FillFlowContainer + ChildrenEnumerable = Enumerable.Range(0, 15).Select(i => new FillFlowContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Spacing = new Vector2(2f), Direction = FillDirection.Vertical, - ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i + j * 0.1f, 0)) + ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i * (i >= 11 ? 25f : 1f) + j * 0.1f, 0)) { Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(width, height), - }) + }), }) }; }); From bf0d4b6ef1c9d20e69c43abb3d945b92ca2c135d Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 8 Aug 2021 10:25:51 +0200 Subject: [PATCH 089/961] Localise basic stats. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 3f1034759e..ce348bd753 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -13,6 +13,7 @@ using osu.Game.Beatmaps; using osu.Game.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Overlays.BeatmapSet @@ -53,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet private void updateDisplay() { - bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToString(@"0.##") ?? "-"; + bpm.Value = BeatmapSet?.OnlineInfo?.BPM.ToLocalisableString(@"0.##") ?? (LocalisableString)"-"; if (beatmap == null) { @@ -63,9 +64,11 @@ namespace osu.Game.Overlays.BeatmapSet } else { + length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration()); length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration(); - circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString(); - sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString(); + + circleCount.Value = beatmap.OnlineInfo.CircleCount.ToLocalisableString("N0"); + sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToLocalisableString("N0"); } } @@ -78,10 +81,10 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Horizontal, Children = new[] { - length = new Statistic(FontAwesome.Regular.Clock, "Length") { Width = 0.25f }, - bpm = new Statistic(FontAwesome.Regular.Circle, "BPM") { Width = 0.25f }, - circleCount = new Statistic(FontAwesome.Regular.Circle, "Circle Count") { Width = 0.25f }, - sliderCount = new Statistic(FontAwesome.Regular.Circle, "Slider Count") { Width = 0.25f }, + length = new Statistic(FontAwesome.Regular.Clock, BeatmapsetsStrings.ShowStatsTotalLength(string.Empty)) { Width = 0.25f }, + bpm = new Statistic(FontAwesome.Regular.Circle, BeatmapsetsStrings.ShowStatsBpm) { Width = 0.25f }, + circleCount = new Statistic(FontAwesome.Regular.Circle, BeatmapsetsStrings.ShowStatsCountCircles) { Width = 0.25f }, + sliderCount = new Statistic(FontAwesome.Regular.Circle, BeatmapsetsStrings.ShowStatsCountSliders) { Width = 0.25f }, }, }; } @@ -96,7 +99,7 @@ namespace osu.Game.Overlays.BeatmapSet { private readonly OsuSpriteText value; - public LocalisableString TooltipText { get; } + public LocalisableString TooltipText { get; set; } public LocalisableString Value { @@ -104,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapSet set => this.value.Text = value; } - public Statistic(IconUsage icon, string name) + public Statistic(IconUsage icon, LocalisableString name) { TooltipText = name; RelativeSizeAxes = Axes.X; From 5e0f9d0af9beffed5189b7cce890b972c5b32413 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 8 Aug 2021 22:00:12 +0200 Subject: [PATCH 090/961] Localise user ratings. --- osu.Game/Screens/Select/Details/UserRatings.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index cf5e3ba1b3..a45bcd0666 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -9,6 +9,8 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using System.Linq; using osu.Game.Beatmaps; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Select.Details { @@ -35,8 +37,8 @@ namespace osu.Game.Screens.Select.Details if (metrics == null) { - negativeRatings.Text = "0"; - positiveRatings.Text = "0"; + negativeRatings.Text = 0.ToLocalisableString("N0"); + positiveRatings.Text = 0.ToLocalisableString("N0"); ratingsBar.Length = 0; graph.Values = new float[rating_range]; } @@ -47,8 +49,8 @@ namespace osu.Game.Screens.Select.Details var negativeCount = ratings.Take(rating_range / 2).Sum(); var totalCount = ratings.Sum(); - negativeRatings.Text = negativeCount.ToString(); - positiveRatings.Text = (totalCount - negativeCount).ToString(); + negativeRatings.Text = negativeCount.ToLocalisableString("N0"); + positiveRatings.Text = (totalCount - negativeCount).ToLocalisableString("N0"); ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; graph.Values = ratings.Take(rating_range).Select(r => (float)r); } @@ -70,7 +72,7 @@ namespace osu.Game.Screens.Select.Details { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = "User Rating", + Text = BeatmapsetsStrings.ShowStatsUserRating, Font = OsuFont.GetFont(size: 12), Margin = new MarginPadding { Bottom = 5 }, }, @@ -88,14 +90,14 @@ namespace osu.Game.Screens.Select.Details { negativeRatings = new OsuSpriteText { - Text = "0", + Text = 0.ToLocalisableString("N0"), Font = OsuFont.GetFont(size: 12) }, positiveRatings = new OsuSpriteText { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Text = @"0", + Text = 0.ToLocalisableString("N0"), Font = OsuFont.GetFont(size: 12) }, }, @@ -104,7 +106,7 @@ namespace osu.Game.Screens.Select.Details { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = "Rating Spread", + Text = BeatmapsetsStrings.ShowStatsRatingSpread, Font = OsuFont.GetFont(size: 12), Margin = new MarginPadding { Bottom = 5 }, }, From 7cb743a734da2bae3b9349e573f25ff0a0a90907 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:17:51 +0900 Subject: [PATCH 091/961] Move font sizing to base class --- osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs | 1 + .../OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs | 1 - .../Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs index cd4dee5e3a..3801463095 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/CreateRoomButton.cs @@ -12,6 +12,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components [BackgroundDependencyLoader] private void load() { + SpriteText.Font = SpriteText.Font.With(size: 14); Triangles.TriangleScale = 1.5f; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs index da141f96dd..e80923ed47 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/CreateMultiplayerMatchButton.cs @@ -22,7 +22,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { - SpriteText.Font = SpriteText.Font.With(size: 14); Text = "Create room"; isConnected = multiplayerClient.IsConnected.GetBoundCopy(); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs index 3fdff8c4b2..a9826a72eb 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/CreatePlaylistsRoomButton.cs @@ -11,7 +11,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [BackgroundDependencyLoader] private void load() { - SpriteText.Font = SpriteText.Font.With(size: 14); Text = "Create playlist"; } } From a12f6b78a4bbd265725f9981229c4dc2f7024c57 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:21:12 +0900 Subject: [PATCH 092/961] Split status retrieval into its own method --- .../OnlinePlay/Lounge/Components/RoomStatusPill.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs index ae17a80705..dfe7ff8cac 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void updateDisplay() { - RoomStatus status = EndDate.Value < DateTimeOffset.Now ? new RoomStatusEnded() : Status.Value ?? new RoomStatusOpen(); + RoomStatus status = getDisplayStatus(); pill.Background.Alpha = 1; pill.Background.FadeColour(status.GetAppropriateColour(colours), firstDisplay ? 0 : 100); @@ -63,5 +63,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components firstDisplay = false; } + + private RoomStatus getDisplayStatus() + { + if (EndDate.Value < DateTimeOffset.Now) + return new RoomStatusEnded(); + + return Status.Value ?? new RoomStatusOpen(); + } } } From f4739d0118eb7340205176f1a96261cf7898e7d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:28:43 +0900 Subject: [PATCH 093/961] Remove `MaskingSmoothness` to avoid making sheered container blurry --- .../OnlinePlay/Lounge/Components/RecentParticipantsList.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index da410716e4..7f3fdf01d0 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -39,7 +39,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { RelativeSizeAxes = Axes.Both, Masking = true, - MaskingSmoothness = 2, CornerRadius = 10, Shear = new Vector2(0.2f, 0), Child = new Box From e08b1223ab7ef6f4d12413ae520fc8f7ca58f260 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 18:23:39 +0900 Subject: [PATCH 094/961] Move team colours to `OsuColour` --- osu.Game.Tournament/TournamentGame.cs | 4 ++-- osu.Game/Graphics/OsuColour.cs | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/TournamentGame.cs b/osu.Game.Tournament/TournamentGame.cs index cd0e601a2f..7a43fee013 100644 --- a/osu.Game.Tournament/TournamentGame.cs +++ b/osu.Game.Tournament/TournamentGame.cs @@ -26,8 +26,8 @@ namespace osu.Game.Tournament { public static ColourInfo GetTeamColour(TeamColour teamColour) => teamColour == TeamColour.Red ? COLOUR_RED : COLOUR_BLUE; - public static readonly Color4 COLOUR_RED = Color4Extensions.FromHex("#AA1414"); - public static readonly Color4 COLOUR_BLUE = Color4Extensions.FromHex("#1462AA"); + public static readonly Color4 COLOUR_RED = new OsuColour().TeamColourRed; + public static readonly Color4 COLOUR_BLUE = new OsuColour().TeamColourBlue; public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = Color4Extensions.FromHex("#fff"); public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = Color4Extensions.FromHex("#000"); diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index 1f87c06dd2..d7cfc4094c 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -130,6 +130,9 @@ namespace osu.Game.Graphics return Gray(brightness > 0.5f ? 0.2f : 0.9f); } + public readonly Color4 TeamColourRed = Color4Extensions.FromHex("#AA1414"); + public readonly Color4 TeamColourBlue = Color4Extensions.FromHex("#1462AA"); + // See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff"); public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff"); From aa4c6b93412e3cacb557d7195bef8bbd8e3d7be3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 17:53:38 +0900 Subject: [PATCH 095/961] Bring across tournament score display for game usage --- .../Components/TestSceneMatchScoreDisplay.cs | 2 +- ...play.cs => TournamentMatchScoreDisplay.cs} | 5 +- .../Screens/Gameplay/GameplayScreen.cs | 4 +- .../Screens/Play/HUD/MatchScoreDisplay.cs | 153 ++++++++++++++++++ 4 files changed, 159 insertions(+), 5 deletions(-) rename osu.Game.Tournament/Screens/Gameplay/Components/{MatchScoreDisplay.cs => TournamentMatchScoreDisplay.cs} (97%) create mode 100644 osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs index acd5d53310..11b5cc7556 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchScoreDisplay.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tournament.Tests.Components public TestSceneMatchScoreDisplay() { - Add(new MatchScoreDisplay + Add(new TournamentMatchScoreDisplay { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs similarity index 97% rename from osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs rename to osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs index 695c6d6f3e..994dee4da0 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/TournamentMatchScoreDisplay.cs @@ -16,7 +16,8 @@ using osuTK; namespace osu.Game.Tournament.Screens.Gameplay.Components { - public class MatchScoreDisplay : CompositeDrawable + // TODO: Update to derive from osu-side class? + public class TournamentMatchScoreDisplay : CompositeDrawable { private const float bar_height = 18; @@ -29,7 +30,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components private readonly Drawable score1Bar; private readonly Drawable score2Bar; - public MatchScoreDisplay() + public TournamentMatchScoreDisplay() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index f61506d7f2..540b45eb56 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -86,7 +86,7 @@ namespace osu.Game.Tournament.Screens.Gameplay }, } }, - scoreDisplay = new MatchScoreDisplay + scoreDisplay = new TournamentMatchScoreDisplay { Y = -147, Anchor = Anchor.BottomCentre, @@ -148,7 +148,7 @@ namespace osu.Game.Tournament.Screens.Gameplay } private ScheduledDelegate scheduledOperation; - private MatchScoreDisplay scoreDisplay; + private TournamentMatchScoreDisplay scoreDisplay; private TourneyState lastState; private MatchHeader header; diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs new file mode 100644 index 0000000000..3df4925972 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -0,0 +1,153 @@ +// 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.Sprites; +using osu.Game.Graphics.UserInterface; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public class MatchScoreDisplay : CompositeDrawable + { + private const float bar_height = 18; + + public BindableInt Team1Score = new BindableInt(); + public BindableInt Team2Score = new BindableInt(); + + private MatchScoreCounter score1Text; + private MatchScoreCounter score2Text; + + private Drawable score1Bar; + private Drawable score2Bar; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChildren = new[] + { + new Box + { + Name = "top bar red (static)", + RelativeSizeAxes = Axes.X, + Height = bar_height / 4, + Width = 0.5f, + Colour = colours.TeamColourRed, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight + }, + new Box + { + Name = "top bar blue (static)", + RelativeSizeAxes = Axes.X, + Height = bar_height / 4, + Width = 0.5f, + Colour = colours.TeamColourBlue, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft + }, + score1Bar = new Box + { + Name = "top bar red", + RelativeSizeAxes = Axes.X, + Height = bar_height, + Width = 0, + Colour = colours.TeamColourRed, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight + }, + score1Text = new MatchScoreCounter + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + score2Bar = new Box + { + Name = "top bar blue", + RelativeSizeAxes = Axes.X, + Height = bar_height, + Width = 0, + Colour = colours.TeamColourBlue, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft + }, + score2Text = new MatchScoreCounter + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Team1Score.BindValueChanged(_ => updateScores()); + Team2Score.BindValueChanged(_ => updateScores()); + } + + private void updateScores() + { + score1Text.Current.Value = Team1Score.Value; + score2Text.Current.Value = Team2Score.Value; + + var winningText = Team1Score.Value > Team2Score.Value ? score1Text : score2Text; + var losingText = Team1Score.Value <= Team2Score.Value ? score1Text : score2Text; + + winningText.Winning = true; + losingText.Winning = false; + + var winningBar = Team1Score.Value > Team2Score.Value ? score1Bar : score2Bar; + var losingBar = Team1Score.Value <= Team2Score.Value ? score1Bar : score2Bar; + + var diff = Math.Max(Team1Score.Value, Team2Score.Value) - Math.Min(Team1Score.Value, Team2Score.Value); + + losingBar.ResizeWidthTo(0, 400, Easing.OutQuint); + winningBar.ResizeWidthTo(Math.Min(0.4f, MathF.Pow(diff / 1500000f, 0.5f) / 2), 400, Easing.OutQuint); + } + + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + score1Text.X = -Math.Max(5 + score1Text.DrawWidth / 2, score1Bar.DrawWidth); + score2Text.X = Math.Max(5 + score2Text.DrawWidth / 2, score2Bar.DrawWidth); + } + + private class MatchScoreCounter : ScoreCounter + { + private OsuSpriteText displayedSpriteText; + + public MatchScoreCounter() + { + Margin = new MarginPadding { Top = bar_height, Horizontal = 10 }; + } + + public bool Winning + { + set => updateFont(value); + } + + protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(s => + { + displayedSpriteText = s; + displayedSpriteText.Spacing = new Vector2(-6); + updateFont(false); + }); + + private void updateFont(bool winning) + => displayedSpriteText.Font = winning + ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true) + : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true); + } + } +} From fcec714b4f545ccc5fbddd4d21a61508f5b7bc62 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 19:01:07 +0900 Subject: [PATCH 096/961] Add safeties to avoid `MultiplayerPlayer` crashing when beatmap can't be loaded --- .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 13 +++++++++++++ osu.Game/Screens/Play/Player.cs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index b54a4a7726..404fc21fc8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -57,6 +57,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { + if (!LoadedBeatmapSuccessfully) + return; + // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); @@ -67,6 +70,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadAsyncComplete(); + if (!LoadedBeatmapSuccessfully) + return; + if (!ValidForResume) return; // token retrieval may have failed. @@ -96,6 +102,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { base.LoadComplete(); + if (!LoadedBeatmapSuccessfully) + return; + ((IBindable)leaderboard.Expanded).BindTo(HUDOverlay.ShowHud); } @@ -118,6 +127,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override void Update() { base.Update(); + + if (!LoadedBeatmapSuccessfully) + return; + adjustLeaderboardPosition(); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 09eaf1c543..1692975210 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -962,7 +962,7 @@ namespace osu.Game.Screens.Play screenSuspension?.Expire(); // if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap. - if (prepareScoreForDisplayTask == null) + if (Score != null && prepareScoreForDisplayTask == null) { Score.ScoreInfo.Passed = false; // potentially should be ScoreRank.F instead? this is the best alternative for now. From 54ffb8dc4e61cce3e37cec371a7067e938074062 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 5 Aug 2021 19:01:16 +0900 Subject: [PATCH 097/961] Add basic multiplayer gameplay test coverage --- .../Multiplayer/TestMultiplayerGameplay.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs new file mode 100644 index 0000000000..4b75121575 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Game.Screens.OnlinePlay.Multiplayer; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestMultiplayerGameplay : MultiplayerTestScene + { + [Test] + public void TestBasic() + { + AddStep("load screen", () => + LoadScreen(new MultiplayerPlayer(Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.Select(u => u.UserID).ToArray()))); + } + } +} From 0fa1f085df9720b6da39342da2ab6f2ae9337bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 6 Aug 2021 20:06:57 +0900 Subject: [PATCH 098/961] Store `MultiplayerRoomUser` as part of tracked data --- .../Multiplayer/Spectate/MultiSpectatorLeaderboard.cs | 7 ++++--- .../Play/HUD/MultiplayerGameplayLeaderboard.cs | 11 +++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs index 55c4270c70..95f9fa27f1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs @@ -4,6 +4,7 @@ using System; using JetBrains.Annotations; using osu.Framework.Timing; +using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play.HUD; @@ -32,7 +33,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate ((SpectatingTrackedUserData)data).Clock = null; } - protected override TrackedUserData CreateUserData(int userId, ScoreProcessor scoreProcessor) => new SpectatingTrackedUserData(userId, scoreProcessor); + protected override TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new SpectatingTrackedUserData(user, scoreProcessor); protected override void Update() { @@ -47,8 +48,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [CanBeNull] public IClock Clock; - public SpectatingTrackedUserData(int userId, ScoreProcessor scoreProcessor) - : base(userId, scoreProcessor) + public SpectatingTrackedUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) + : base(user, scoreProcessor) { } diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index a10c16fcd5..74e5710677 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -11,6 +11,7 @@ using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; @@ -55,7 +56,9 @@ namespace osu.Game.Screens.Play.HUD foreach (var userId in playingUsers) { - var trackedUser = CreateUserData(userId, scoreProcessor); + var user = multiplayerClient.Room?.Users.FirstOrDefault(u => u.UserID == userId); + + var trackedUser = CreateUserData(user, scoreProcessor); trackedUser.ScoringMode.BindTo(scoringMode); UserScores[userId] = trackedUser; } @@ -145,7 +148,7 @@ namespace osu.Game.Screens.Play.HUD protected class TrackedUserData { - public readonly int UserId; + public readonly MultiplayerRoomUser User; public readonly ScoreProcessor ScoreProcessor; public readonly BindableDouble Score = new BindableDouble(); @@ -157,9 +160,9 @@ namespace osu.Game.Screens.Play.HUD public readonly List Frames = new List(); - public TrackedUserData(int userId, ScoreProcessor scoreProcessor) + public TrackedUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) { - UserId = userId; + User = user; ScoreProcessor = scoreProcessor; ScoringMode.BindValueChanged(_ => UpdateScore()); From 1e5d9003d389d3ef882c4aa9c3d63c2f0a63f887 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:44:50 +0900 Subject: [PATCH 099/961] Add the ability for tests to alter the room and user states which during testing --- ...TestSceneMultiplayerGameplayLeaderboard.cs | 4 +++ .../Multiplayer/MultiplayerTestScene.cs | 29 +++++++++++-------- .../Multiplayer/TestMultiplayerClient.cs | 7 ++++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 0e368b59dd..0aa47f0899 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -20,6 +20,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play.HUD; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Tests.Visual.Spectator; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -53,7 +54,10 @@ namespace osu.Game.Tests.Visual.Multiplayer var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); foreach (var user in users) + { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); + OnlinePlayDependencies.Client.AddUser(new User { Id = user }); + } // Todo: This is REALLY bad. Client.CurrentMatchPlayingUserIds.AddRange(users); diff --git a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs index 42345b7266..f259784170 100644 --- a/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/Multiplayer/MultiplayerTestScene.cs @@ -36,24 +36,29 @@ namespace osu.Game.Tests.Visual.Multiplayer { if (joinRoom) { - var room = new Room - { - Name = { Value = "test name" }, - Playlist = - { - new PlaylistItem - { - Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, - Ruleset = { Value = Ruleset.Value } - } - } - }; + var room = CreateRoom(); RoomManager.CreateRoom(room); SelectedRoom.Value = room; } }); + protected virtual Room CreateRoom() + { + return new Room + { + Name = { Value = "test name" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, + Ruleset = { Value = Ruleset.Value } + } + } + }; + } + public override void SetUpSteps() { base.SetUpSteps(); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 43aadf5acb..db491aac25 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -50,7 +50,12 @@ namespace osu.Game.Tests.Visual.Multiplayer public void Disconnect() => isConnected.Value = false; - public void AddUser(User user) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(user.Id) { User = user }); + public MultiplayerRoomUser AddUser(User user) + { + var roomUser = new MultiplayerRoomUser(user.Id) { User = user }; + ((IMultiplayerClient)this).UserJoined(roomUser); + return roomUser; + } public void AddNullUser(int userId) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(userId)); From ab522e1569e23000df98840a2f286f233a973284 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:50:25 +0900 Subject: [PATCH 100/961] Add test coverage of team display on leaderboard --- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs new file mode 100644 index 0000000000..0551f3b802 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -0,0 +1,99 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Configuration; +using osu.Game.Online.API; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Screens.Play.HUD; +using osu.Game.Tests.Visual.OnlinePlay; +using osu.Game.Tests.Visual.Spectator; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMultiplayerGameplayLeaderboardTeams : MultiplayerTestScene + { + private static IEnumerable users => Enumerable.Range(0, 16); + + public new TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient SpectatorClient => + (TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient)OnlinePlayDependencies?.SpectatorClient; + + protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies(); + + protected class TestDependencies : MultiplayerTestSceneDependencies + { + protected override TestSpectatorClient CreateSpectatorClient() => new TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient(); + } + + private MultiplayerGameplayLeaderboard leaderboard; + + protected override Room CreateRoom() + { + var room = base.CreateRoom(); + room.Type.Value = MatchType.TeamVersus; + return room; + } + + [SetUpSteps] + public override void SetUpSteps() + { + AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = LookupCache.GetUserAsync(1).Result); + + AddStep("create leaderboard", () => + { + leaderboard?.Expire(); + + OsuScoreProcessor scoreProcessor; + Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); + + var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + + foreach (var user in users) + { + SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); + var roomUser = OnlinePlayDependencies.Client.AddUser(new User { Id = user }); + + roomUser.MatchState = new TeamVersusUserState + { + TeamID = RNG.Next(0, 2) + }; + } + + // Todo: This is REALLY bad. + Client.CurrentMatchPlayingUserIds.AddRange(users); + + Children = new Drawable[] + { + scoreProcessor = new OsuScoreProcessor(), + }; + + scoreProcessor.ApplyBeatmap(playable); + + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, users.ToArray()) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }, Add); + }); + + AddUntilStep("wait for load", () => leaderboard.IsLoaded); + AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0); + } + + [Test] + public void TestScoreUpdates() + { + AddRepeatStep("update state", () => SpectatorClient.RandomlyUpdateState(), 100); + AddToggleStep("switch compact mode", expanded => leaderboard.Expanded.Value = expanded); + } + } +} From e1d4eee1d2439167fa2362deaffe3dcb137956c6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 16:59:24 +0900 Subject: [PATCH 101/961] Add the ability to set custom overriding colours on `GameplayLeaderboardScore`s --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 10 ++++++---- .../Screens/Play/HUD/GameplayLeaderboardScore.cs | 16 ++++++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 34efeab54c..63cb4f89f5 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -48,10 +48,9 @@ namespace osu.Game.Screens.Play.HUD /// public ILeaderboardScore AddPlayer([CanBeNull] User user, bool isTracked) { - var drawable = new GameplayLeaderboardScore(user, isTracked) - { - Expanded = { BindTarget = Expanded }, - }; + var drawable = CreateLeaderboardScoreDrawable(user, isTracked); + + drawable.Expanded.BindTo(Expanded); base.Add(drawable); drawable.TotalScore.BindValueChanged(_ => sorting.Invalidate(), true); @@ -61,6 +60,9 @@ namespace osu.Game.Screens.Play.HUD return drawable; } + protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) => + new GameplayLeaderboardScore(user, isTracked); + public sealed override void Add(GameplayLeaderboardScore drawable) { throw new NotSupportedException($"Use {nameof(AddPlayer)} instead."); diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 10476e5565..433bf78e9b 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -54,6 +54,10 @@ namespace osu.Game.Screens.Play.HUD public BindableInt Combo { get; } = new BindableInt(); public BindableBool HasQuit { get; } = new BindableBool(); + public Color4? BackgroundColour { get; set; } + + public Color4? TextColour { get; set; } + private int? scorePosition; public int? ScorePosition @@ -331,19 +335,19 @@ namespace osu.Game.Screens.Play.HUD if (scorePosition == 1) { widthExtension = true; - panelColour = Color4Extensions.FromHex("7fcc33"); - textColour = Color4.White; + panelColour = BackgroundColour ?? Color4Extensions.FromHex("7fcc33"); + textColour = TextColour ?? Color4.White; } else if (trackedPlayer) { widthExtension = true; - panelColour = Color4Extensions.FromHex("ffd966"); - textColour = Color4Extensions.FromHex("2e576b"); + panelColour = BackgroundColour ?? Color4Extensions.FromHex("ffd966"); + textColour = TextColour ?? Color4Extensions.FromHex("2e576b"); } else { - panelColour = Color4Extensions.FromHex("3399cc"); - textColour = Color4.White; + panelColour = BackgroundColour ?? Color4Extensions.FromHex("3399cc"); + textColour = TextColour ?? Color4.White; } this.TransformTo(nameof(SizeContainerLeftPadding), widthExtension ? -top_player_left_width_extension : 0, panel_transition_duration, Easing.OutElastic); From 77c9aadd05d3495a9f55bbf6d54c19305ca821ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 17:04:06 +0900 Subject: [PATCH 102/961] Add team colour support to multiplaye gameplay leaderboard panels --- .../HUD/MultiplayerGameplayLeaderboard.cs | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 74e5710677..36a0365775 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -7,13 +7,17 @@ using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Game.Configuration; using osu.Game.Database; +using osu.Game.Graphics; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; -using osu.Game.Online.Rooms; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Spectator; using osu.Game.Rulesets.Scoring; +using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { @@ -103,6 +107,34 @@ namespace osu.Game.Screens.Play.HUD spectatorClient.OnNewFrames += handleIncomingFrames; } + [Resolved] + private OsuColour colours { get; set; } + + protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) + { + var leaderboardScore = base.CreateLeaderboardScoreDrawable(user, isTracked); + + if (UserScores[user.Id].Team is int team) + { + leaderboardScore.BackgroundColour = getTeamColour(team).Lighten(1.2f); + leaderboardScore.TextColour = Color4.White; + } + + return leaderboardScore; + } + + private Color4 getTeamColour(int team) + { + switch (team) + { + case 0: + return colours.TeamColourRed; + + default: + return colours.TeamColourBlue; + } + } + private void usersChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) @@ -129,7 +161,7 @@ namespace osu.Game.Screens.Play.HUD trackedData.UpdateScore(); }); - protected virtual TrackedUserData CreateUserData(int userId, ScoreProcessor scoreProcessor) => new TrackedUserData(userId, scoreProcessor); + protected virtual TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new TrackedUserData(user, scoreProcessor); protected override void Dispose(bool isDisposing) { @@ -160,6 +192,8 @@ namespace osu.Game.Screens.Play.HUD public readonly List Frames = new List(); + public int? Team => (User.MatchState as TeamVersusUserState)?.TeamID; + public TrackedUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) { User = user; From cdc173e86782026e7d6b11f3b9d0f3af26fbb672 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 17:07:50 +0900 Subject: [PATCH 103/961] Add tracking of team totals to leaderboard implementation --- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 6 ++++ .../HUD/MultiplayerGameplayLeaderboard.cs | 32 +++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 0551f3b802..6376d4e305 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -83,6 +83,12 @@ namespace osu.Game.Tests.Visual.Multiplayer Anchor = Anchor.Centre, Origin = Anchor.Centre, }, Add); + + LoadComponentAsync(new MatchScoreDisplay + { + Team1Score = { BindTarget = leaderboard.Team1Score }, + Team2Score = { BindTarget = leaderboard.Team2Score } + }, Add); }); AddUntilStep("wait for load", () => leaderboard.IsLoaded); diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 36a0365775..19019e61f0 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -26,6 +26,12 @@ namespace osu.Game.Screens.Play.HUD { protected readonly Dictionary UserScores = new Dictionary(); + public readonly BindableInt Team1Score = new BindableInt(); + public readonly BindableInt Team2Score = new BindableInt(); + + [Resolved] + private OsuColour colours { get; set; } + [Resolved] private SpectatorClient spectatorClient { get; set; } @@ -39,6 +45,8 @@ namespace osu.Game.Screens.Play.HUD private readonly BindableList playingUsers; private Bindable scoringMode; + private bool hasTeams; + /// /// Construct a new leaderboard. /// @@ -65,6 +73,8 @@ namespace osu.Game.Screens.Play.HUD var trackedUser = CreateUserData(user, scoreProcessor); trackedUser.ScoringMode.BindTo(scoringMode); UserScores[userId] = trackedUser; + + hasTeams |= trackedUser.Team != null; } userLookupCache.GetUsersAsync(playingUsers.ToArray()).ContinueWith(users => Schedule(() => @@ -107,8 +117,7 @@ namespace osu.Game.Screens.Play.HUD spectatorClient.OnNewFrames += handleIncomingFrames; } - [Resolved] - private OsuColour colours { get; set; } + protected virtual TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new TrackedUserData(user, scoreProcessor); protected override GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) { @@ -159,9 +168,26 @@ namespace osu.Game.Screens.Play.HUD trackedData.Frames.Add(new TimedFrame(bundle.Frames.First().Time, bundle.Header)); trackedData.UpdateScore(); + + updateTotals(); }); - protected virtual TrackedUserData CreateUserData(MultiplayerRoomUser user, ScoreProcessor scoreProcessor) => new TrackedUserData(user, scoreProcessor); + private void updateTotals() + { + if (!hasTeams) + return; + + Team1Score.Value = 0; + Team2Score.Value = 0; + + foreach (var u in UserScores.Values) + { + if (u.Team == 0) + Team1Score.Value += (int)u.Score.Value; + else + Team2Score.Value += (int)u.Score.Value; + } + } protected override void Dispose(bool isDisposing) { From ebbf6467e815091149460b54b2ed6f5fec97e5b9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 17:23:02 +0900 Subject: [PATCH 104/961] Support more than two teams --- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 17 ++++++++-------- .../HUD/MultiplayerGameplayLeaderboard.cs | 20 +++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 6376d4e305..ce3add84c5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -4,11 +4,9 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Configuration; using osu.Game.Online.API; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; @@ -82,13 +80,16 @@ namespace osu.Game.Tests.Visual.Multiplayer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - }, Add); - - LoadComponentAsync(new MatchScoreDisplay + }, gameplayLeaderboard => { - Team1Score = { BindTarget = leaderboard.Team1Score }, - Team2Score = { BindTarget = leaderboard.Team2Score } - }, Add); + LoadComponentAsync(new MatchScoreDisplay + { + Team1Score = { BindTarget = leaderboard.TeamScores[0] }, + Team2Score = { BindTarget = leaderboard.TeamScores[1] } + }, Add); + + Add(gameplayLeaderboard); + }); }); AddUntilStep("wait for load", () => leaderboard.IsLoaded); diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 19019e61f0..2895d0cb5c 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -26,8 +26,7 @@ namespace osu.Game.Screens.Play.HUD { protected readonly Dictionary UserScores = new Dictionary(); - public readonly BindableInt Team1Score = new BindableInt(); - public readonly BindableInt Team2Score = new BindableInt(); + public readonly Dictionary TeamScores = new Dictionary(); [Resolved] private OsuColour colours { get; set; } @@ -45,7 +44,7 @@ namespace osu.Game.Screens.Play.HUD private readonly BindableList playingUsers; private Bindable scoringMode; - private bool hasTeams; + private bool hasTeams => TeamScores.Count > 0; /// /// Construct a new leaderboard. @@ -74,7 +73,8 @@ namespace osu.Game.Screens.Play.HUD trackedUser.ScoringMode.BindTo(scoringMode); UserScores[userId] = trackedUser; - hasTeams |= trackedUser.Team != null; + if (trackedUser.Team is int team && !TeamScores.ContainsKey(team)) + TeamScores.Add(team, new BindableInt()); } userLookupCache.GetUsersAsync(playingUsers.ToArray()).ContinueWith(users => Schedule(() => @@ -177,15 +177,15 @@ namespace osu.Game.Screens.Play.HUD if (!hasTeams) return; - Team1Score.Value = 0; - Team2Score.Value = 0; + foreach (var scores in TeamScores.Values) scores.Value = 0; foreach (var u in UserScores.Values) { - if (u.Team == 0) - Team1Score.Value += (int)u.Score.Value; - else - Team2Score.Value += (int)u.Score.Value; + if (u.Team == null) + continue; + + if (TeamScores.TryGetValue(u.Team.Value, out var team)) + team.Value += (int)u.Score.Value; } } From 121648b5937f6370183bbb0a184973d3f8436f82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 18:13:28 +0900 Subject: [PATCH 105/961] Add gameplay-specific team score display which can expand and contract --- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 16 ++++++- .../Multiplayer/GameplayMatchScoreDisplay.cs | 40 ++++++++++++++++++ .../Multiplayer/MultiplayerPlayer.cs | 42 +++++++++++++------ .../Screens/Play/HUD/MatchScoreDisplay.cs | 42 ++++++++++++------- 4 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index ce3add84c5..8eaa63a166 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -11,6 +11,7 @@ using osu.Game.Online.API; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.Play.HUD; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Tests.Visual.Spectator; @@ -33,6 +34,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } private MultiplayerGameplayLeaderboard leaderboard; + private GameplayMatchScoreDisplay gameplayScoreDisplay; protected override Room CreateRoom() { @@ -88,6 +90,14 @@ namespace osu.Game.Tests.Visual.Multiplayer Team2Score = { BindTarget = leaderboard.TeamScores[1] } }, Add); + LoadComponentAsync(gameplayScoreDisplay = new GameplayMatchScoreDisplay + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Team1Score = { BindTarget = leaderboard.TeamScores[0] }, + Team2Score = { BindTarget = leaderboard.TeamScores[1] } + }, Add); + Add(gameplayLeaderboard); }); }); @@ -100,7 +110,11 @@ namespace osu.Game.Tests.Visual.Multiplayer public void TestScoreUpdates() { AddRepeatStep("update state", () => SpectatorClient.RandomlyUpdateState(), 100); - AddToggleStep("switch compact mode", expanded => leaderboard.Expanded.Value = expanded); + AddToggleStep("switch compact mode", expanded => + { + leaderboard.Expanded.Value = expanded; + gameplayScoreDisplay.Expanded.Value = expanded; + }); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.cs new file mode 100644 index 0000000000..20a88545c5 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayMatchScoreDisplay.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 osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer +{ + public class GameplayMatchScoreDisplay : MatchScoreDisplay + { + public Bindable Expanded = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + Scale = new Vector2(0.5f); + + Expanded.BindValueChanged(expandedChanged, true); + } + + private void expandedChanged(ValueChangedEvent expanded) + { + if (expanded.NewValue) + { + Score1Text.FadeIn(500, Easing.OutQuint); + Score2Text.FadeIn(500, Easing.OutQuint); + this.ResizeWidthTo(2, 500, Easing.OutQuint); + } + else + { + Score1Text.FadeOut(500, Easing.OutQuint); + Score2Text.FadeOut(500, Easing.OutQuint); + this.ResizeWidthTo(1, 500, Easing.OutQuint); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 404fc21fc8..0ff7d70c11 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -3,9 +3,12 @@ using System; using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Multiplayer; @@ -37,6 +40,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private readonly int[] userIds; private LoadingLayer loadingDisplay; + private FillFlowContainer leaderboardFlow; /// /// Construct a multiplayer player. @@ -60,8 +64,32 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (!LoadedBeatmapSuccessfully) return; + HUDOverlay.Add(leaderboardFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + }); + // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), HUDOverlay.Add); + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), l => + { + if (!LoadedBeatmapSuccessfully) + return; + + ((IBindable)leaderboard.Expanded).BindTo(HUDOverlay.ShowHud); + + leaderboardFlow.Add(l); + + if (leaderboard.TeamScores.Count >= 2) + { + LoadComponentAsync(new GameplayMatchScoreDisplay + { + Team1Score = { BindTarget = leaderboard.TeamScores.First().Value }, + Team2Score = { BindTarget = leaderboard.TeamScores.Last().Value }, + Expanded = { BindTarget = HUDOverlay.ShowHud }, + }, leaderboardFlow.Add); + } + }); HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue }); } @@ -98,16 +126,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Debug.Assert(client.Room != null); } - protected override void LoadComplete() - { - base.LoadComplete(); - - if (!LoadedBeatmapSuccessfully) - return; - - ((IBindable)leaderboard.Expanded).BindTo(HUDOverlay.ShowHud); - } - protected override void StartGameplay() { // block base call, but let the server know we are ready to start. @@ -138,7 +156,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { const float padding = 44; // enough margin to avoid the hit error display. - leaderboard.Position = new Vector2(padding, padding + HUDOverlay.TopScoringElementsHeight); + leaderboardFlow.Position = new Vector2(padding, padding + HUDOverlay.TopScoringElementsHeight); } private void onMatchStarted() => Scheduler.Add(() => diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index 3df4925972..d25ceb948e 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -21,8 +21,8 @@ namespace osu.Game.Screens.Play.HUD public BindableInt Team1Score = new BindableInt(); public BindableInt Team2Score = new BindableInt(); - private MatchScoreCounter score1Text; - private MatchScoreCounter score2Text; + protected MatchScoreCounter Score1Text; + protected MatchScoreCounter Score2Text; private Drawable score1Bar; private Drawable score2Bar; @@ -65,11 +65,6 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.TopCentre, Origin = Anchor.TopRight }, - score1Text = new MatchScoreCounter - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - }, score2Bar = new Box { Name = "top bar blue", @@ -80,10 +75,25 @@ namespace osu.Game.Screens.Play.HUD Anchor = Anchor.TopCentre, Origin = Anchor.TopLeft }, - score2Text = new MatchScoreCounter + new Container { + RelativeSizeAxes = Axes.X, + Height = 50, Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre + Origin = Anchor.TopCentre, + Children = new Drawable[] + { + Score1Text = new MatchScoreCounter + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + Score2Text = new MatchScoreCounter + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + }, + } }, }; } @@ -98,11 +108,11 @@ namespace osu.Game.Screens.Play.HUD private void updateScores() { - score1Text.Current.Value = Team1Score.Value; - score2Text.Current.Value = Team2Score.Value; + Score1Text.Current.Value = Team1Score.Value; + Score2Text.Current.Value = Team2Score.Value; - var winningText = Team1Score.Value > Team2Score.Value ? score1Text : score2Text; - var losingText = Team1Score.Value <= Team2Score.Value ? score1Text : score2Text; + var winningText = Team1Score.Value > Team2Score.Value ? Score1Text : Score2Text; + var losingText = Team1Score.Value <= Team2Score.Value ? Score1Text : Score2Text; winningText.Winning = true; losingText.Winning = false; @@ -119,11 +129,11 @@ namespace osu.Game.Screens.Play.HUD protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - score1Text.X = -Math.Max(5 + score1Text.DrawWidth / 2, score1Bar.DrawWidth); - score2Text.X = Math.Max(5 + score2Text.DrawWidth / 2, score2Bar.DrawWidth); + Score1Text.X = -Math.Max(5 + Score1Text.DrawWidth / 2, score1Bar.DrawWidth); + Score2Text.X = Math.Max(5 + Score2Text.DrawWidth / 2, score2Bar.DrawWidth); } - private class MatchScoreCounter : ScoreCounter + protected class MatchScoreCounter : ScoreCounter { private OsuSpriteText displayedSpriteText; From 5f3d0871012f88bf1bfba1d7cb309ad69b372384 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 19:05:23 +0900 Subject: [PATCH 106/961] Also add team score display to multiplayer spectator screen --- .../TestSceneMultiSpectatorLeaderboard.cs | 4 ++ .../TestSceneMultiSpectatorScreen.cs | 43 ++++++++++++++++++ .../Spectate/MultiSpectatorScreen.cs | 44 +++++++++++++++---- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index e14df62af1..22543b7b26 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -9,6 +9,7 @@ using osu.Framework.Timing; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play.HUD; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -31,7 +32,10 @@ namespace osu.Game.Tests.Visual.Multiplayer }; foreach (var (userId, _) in clocks) + { SpectatorClient.StartPlay(userId, 0); + OnlinePlayDependencies.Client.AddUser(new User { Id = userId }); + } }); AddStep("create leaderboard", () => diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 072e32370d..e8ee9fe012 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -8,10 +8,12 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Rulesets.UI; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { @@ -49,6 +51,10 @@ namespace osu.Game.Tests.Visual.Multiplayer { Client.CurrentMatchPlayingUserIds.Add(PLAYER_1_ID); Client.CurrentMatchPlayingUserIds.Add(PLAYER_2_ID); + + OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }); + OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }); + playingUserIds.Add(PLAYER_1_ID); playingUserIds.Add(PLAYER_2_ID); }); @@ -76,6 +82,41 @@ namespace osu.Game.Tests.Visual.Multiplayer AddWaitStep("wait a bit", 20); } + [Test] + public void TestTeamDisplay() + { + AddStep("start players", () => + { + Client.CurrentMatchPlayingUserIds.Add(PLAYER_1_ID); + Client.CurrentMatchPlayingUserIds.Add(PLAYER_2_ID); + + var player1 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }); + player1.MatchState = new TeamVersusUserState + { + TeamID = 0, + }; + + var player2 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }); + player2.MatchState = new TeamVersusUserState + { + TeamID = 1, + }; + + SpectatorClient.StartPlay(PLAYER_1_ID, importedBeatmapId); + SpectatorClient.StartPlay(PLAYER_2_ID, importedBeatmapId); + + playingUserIds.Add(PLAYER_1_ID); + playingUserIds.Add(PLAYER_2_ID); + }); + + loadSpectateScreen(); + + sendFrames(PLAYER_1_ID, 1000); + sendFrames(PLAYER_2_ID, 1000); + + AddWaitStep("wait a bit", 20); + } + [Test] public void TestTimeDoesNotProgressWhileAllPlayersPaused() { @@ -265,6 +306,8 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (int id in userIds) { Client.CurrentMatchPlayingUserIds.Add(id); + OnlinePlayDependencies.Client.AddUser(new User { Id = id }); + SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId); playingUserIds.Add(id); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 56ed7a9564..9923c42583 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Spectate; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate @@ -59,6 +60,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void load() { Container leaderboardContainer; + Container scoreDisplayContainer; + masterClockContainer = new MasterGameplayClockContainer(Beatmap.Value, 0); InternalChildren = new[] @@ -67,20 +70,36 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate masterClockContainer.WithChild(new GridContainer { RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, Content = new[] { new Drawable[] { - leaderboardContainer = new Container + scoreDisplayContainer = new Container { - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, - grid = new PlayerGrid { RelativeSizeAxes = Axes.Both } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = new[] + { + new Drawable[] + { + leaderboardContainer = new Container + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }, + grid = new PlayerGrid { RelativeSizeAxes = Axes.Both } + } + } + } } } }) @@ -108,6 +127,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate leaderboard.AddClock(instance.UserId, instance.GameplayClock); leaderboardContainer.Add(leaderboard); + + if (leaderboard.TeamScores.Count >= 2) + { + LoadComponentAsync(new MatchScoreDisplay + { + Team1Score = { BindTarget = leaderboard.TeamScores.First().Value }, + Team2Score = { BindTarget = leaderboard.TeamScores.Last().Value }, + }, scoreDisplayContainer.Add); + } }); } From 551929cf5ad214fce24e99f6d76d185ae6ff8987 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 19:18:13 +0900 Subject: [PATCH 107/961] Simplify method of marking players as playing in test scenes --- .../TestSceneMultiSpectatorScreen.cs | 17 +++++------------ .../TestSceneMultiplayerGameplayLeaderboard.cs | 5 +---- ...tSceneMultiplayerGameplayLeaderboardTeams.cs | 5 +---- .../Online/Multiplayer/MultiplayerClient.cs | 14 ++++++++------ .../Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- .../Visual/Multiplayer/TestMultiplayerClient.cs | 6 +++++- 6 files changed, 21 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index e8ee9fe012..116349c71e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -49,11 +49,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("start players silently", () => { - Client.CurrentMatchPlayingUserIds.Add(PLAYER_1_ID); - Client.CurrentMatchPlayingUserIds.Add(PLAYER_2_ID); - - OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }); - OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }); + OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true); + OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true); playingUserIds.Add(PLAYER_1_ID); playingUserIds.Add(PLAYER_2_ID); @@ -87,16 +84,13 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("start players", () => { - Client.CurrentMatchPlayingUserIds.Add(PLAYER_1_ID); - Client.CurrentMatchPlayingUserIds.Add(PLAYER_2_ID); - - var player1 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }); + var player1 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true); player1.MatchState = new TeamVersusUserState { TeamID = 0, }; - var player2 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }); + var player2 = OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true); player2.MatchState = new TeamVersusUserState { TeamID = 1, @@ -305,8 +299,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { foreach (int id in userIds) { - Client.CurrentMatchPlayingUserIds.Add(id); - OnlinePlayDependencies.Client.AddUser(new User { Id = id }); + OnlinePlayDependencies.Client.AddUser(new User { Id = id }, true); SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId); playingUserIds.Add(id); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 0aa47f0899..8121492a0b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -56,12 +56,9 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (var user in users) { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - OnlinePlayDependencies.Client.AddUser(new User { Id = user }); + OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true); } - // Todo: This is REALLY bad. - Client.CurrentMatchPlayingUserIds.AddRange(users); - Children = new Drawable[] { scoreProcessor = new OsuScoreProcessor(), diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 8eaa63a166..d363c6eed4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -60,7 +60,7 @@ namespace osu.Game.Tests.Visual.Multiplayer foreach (var user in users) { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - var roomUser = OnlinePlayDependencies.Client.AddUser(new User { Id = user }); + var roomUser = OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true); roomUser.MatchState = new TeamVersusUserState { @@ -68,9 +68,6 @@ namespace osu.Game.Tests.Visual.Multiplayer }; } - // Todo: This is REALLY bad. - Client.CurrentMatchPlayingUserIds.AddRange(users); - Children = new Drawable[] { scoreProcessor = new OsuScoreProcessor(), diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index bffb2d341a..14beb38cde 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -62,7 +62,9 @@ namespace osu.Game.Online.Multiplayer /// /// The users in the joined which are participating in the current gameplay loop. /// - public readonly BindableList CurrentMatchPlayingUserIds = new BindableList(); + public IBindableList CurrentMatchPlayingUserIds => PlayingUserIds; + + protected readonly BindableList PlayingUserIds = new BindableList(); public readonly Bindable CurrentMatchPlayingItem = new Bindable(); @@ -179,7 +181,7 @@ namespace osu.Game.Online.Multiplayer { APIRoom = null; Room = null; - CurrentMatchPlayingUserIds.Clear(); + PlayingUserIds.Clear(); RoomUpdated?.Invoke(); }); @@ -376,7 +378,7 @@ namespace osu.Game.Online.Multiplayer return; Room.Users.Remove(user); - CurrentMatchPlayingUserIds.Remove(user.UserID); + PlayingUserIds.Remove(user.UserID); RoomUpdated?.Invoke(); }, false); @@ -659,16 +661,16 @@ namespace osu.Game.Online.Multiplayer /// The new state of the user. private void updateUserPlayingState(int userId, MultiplayerUserState state) { - bool wasPlaying = CurrentMatchPlayingUserIds.Contains(userId); + bool wasPlaying = PlayingUserIds.Contains(userId); bool isPlaying = state >= MultiplayerUserState.WaitingForLoad && state <= MultiplayerUserState.FinishedPlay; if (isPlaying == wasPlaying) return; if (isPlaying) - CurrentMatchPlayingUserIds.Add(userId); + PlayingUserIds.Add(userId); else - CurrentMatchPlayingUserIds.Remove(userId); + PlayingUserIds.Remove(userId); } private Task scheduleAsync(Action action, CancellationToken cancellationToken = default) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 2895d0cb5c..4968dc0706 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play.HUD private UserLookupCache userLookupCache { get; set; } private readonly ScoreProcessor scoreProcessor; - private readonly BindableList playingUsers; + private readonly IBindableList playingUsers; private Bindable scoringMode; private bool hasTeams => TeamScores.Count > 0; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index db491aac25..cffaea5c94 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -50,10 +50,14 @@ namespace osu.Game.Tests.Visual.Multiplayer public void Disconnect() => isConnected.Value = false; - public MultiplayerRoomUser AddUser(User user) + public MultiplayerRoomUser AddUser(User user, bool markAsPlaying = false) { var roomUser = new MultiplayerRoomUser(user.Id) { User = user }; ((IMultiplayerClient)this).UserJoined(roomUser); + + if (markAsPlaying) + PlayingUserIds.Add(user.Id); + return roomUser; } From 490f9e18486ba5abd03c2300b802f0c193b14df4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 19:45:16 +0900 Subject: [PATCH 108/961] Fix overlap in spectator view --- osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index d25ceb948e..837d8bfde7 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -17,6 +17,7 @@ namespace osu.Game.Screens.Play.HUD public class MatchScoreDisplay : CompositeDrawable { private const float bar_height = 18; + private const float font_size = 50; public BindableInt Team1Score = new BindableInt(); public BindableInt Team2Score = new BindableInt(); @@ -78,7 +79,7 @@ namespace osu.Game.Screens.Play.HUD new Container { RelativeSizeAxes = Axes.X, - Height = 50, + Height = font_size + bar_height, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Children = new Drawable[] @@ -156,8 +157,8 @@ namespace osu.Game.Screens.Play.HUD private void updateFont(bool winning) => displayedSpriteText.Font = winning - ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true) - : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true); + ? OsuFont.Torus.With(weight: FontWeight.Bold, size: font_size, fixedWidth: true) + : OsuFont.Torus.With(weight: FontWeight.Regular, size: font_size * 0.8f, fixedWidth: true); } } } From 58714dbe719ee3b5544166e3791d962046fa21b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 9 Aug 2021 19:48:53 +0900 Subject: [PATCH 109/961] Fix ordering of teams to match colours --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 4968dc0706..013d266ac2 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -26,7 +26,7 @@ namespace osu.Game.Screens.Play.HUD { protected readonly Dictionary UserScores = new Dictionary(); - public readonly Dictionary TeamScores = new Dictionary(); + public readonly SortedDictionary TeamScores = new SortedDictionary(); [Resolved] private OsuColour colours { get; set; } From 0b41731d0bb5ffef7219d3d7e64011e3fd26dc62 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 11:43:11 +0700 Subject: [PATCH 110/961] initial changelog supporter promo section --- .../Changelog/ChangelogSingleBuild.cs | 1 + .../Changelog/ChangelogSupporterPromo.cs | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 8b89d63aab..25d8eaf0db 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -71,6 +71,7 @@ namespace osu.Game.Overlays.Changelog Colour = colourProvider.Background6, Margin = new MarginPadding { Top = 30 }, }, + new ChangelogSupporterPromo(), comments = new CommentsContainer() }; diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs new file mode 100644 index 0000000000..98b3cc2002 --- /dev/null +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -0,0 +1,46 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Changelog +{ + public class ChangelogSupporterPromo : CompositeDrawable + { + public ChangelogSupporterPromo() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding + { + Vertical = 20, + Horizontal = 50, + }; + InternalChildren = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0.3f), + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + Height = 200, + }, + } + }, + }; + } + } +} From bdf6c2a5edf61d89dcb095acd86672c1367e07e2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 12:00:26 +0700 Subject: [PATCH 111/961] add changelog supporter promo test scene --- .../TestSceneChangelogSupporterPromo.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs new file mode 100644 index 0000000000..22220a7d9c --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogSupporterPromo.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Overlays; +using osu.Game.Overlays.Changelog; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneChangelogSupporterPromo : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + + public TestSceneChangelogSupporterPromo() + { + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + new ChangelogSupporterPromo(), + } + }; + } + } +} From a2b4f05ebe311527ec77351c293f5a111e5535a7 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 12:11:21 +0700 Subject: [PATCH 112/961] add border radius and shadow --- .../Overlays/Changelog/ChangelogSupporterPromo.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 98b3cc2002..0775ba4494 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -4,7 +4,9 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osuTK; using osuTK.Graphics; namespace osu.Game.Overlays.Changelog @@ -26,6 +28,15 @@ namespace osu.Game.Overlays.Changelog { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Masking = true, + CornerRadius = 6, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Offset = new Vector2(0, 1), + Radius = 3, + }, Children = new Drawable[] { new Box From 7c8df571090813a641c86b0ca215b234a6b9acf6 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 13:21:23 +0700 Subject: [PATCH 113/961] add description text --- .../Changelog/ChangelogSupporterPromo.cs | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 0775ba4494..ba5cac731b 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -1,11 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -13,6 +19,9 @@ namespace osu.Game.Overlays.Changelog { public class ChangelogSupporterPromo : CompositeDrawable { + private readonly LinkFlowContainer supportLinkText; + private readonly TextFlowContainer supportNoteText; + public ChangelogSupporterPromo() { RelativeSizeAxes = Axes.X; @@ -22,6 +31,7 @@ namespace osu.Game.Overlays.Changelog Vertical = 20, Horizontal = 50, }; + InternalChildren = new Drawable[] { new Container @@ -48,10 +58,67 @@ namespace osu.Game.Overlays.Changelog { RelativeSizeAxes = Axes.X, Height = 200, + Padding = new MarginPadding { Horizontal = 75 }, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = ChangelogStrings.SupportHeading, + Font = OsuFont.GetFont(size: 22, weight: FontWeight.Light), + Margin = new MarginPadding { Bottom = 20 }, + }, + supportLinkText = new LinkFlowContainer(t => + { + t.Font = t.Font.With(size: 17.5f); + }) + { + AutoSizeAxes = Axes.Both, + }, + supportNoteText = new TextFlowContainer(t => + { + t.Font = t.Font.With(size: 15); + }) + { + Margin = new MarginPadding { Top = 10 }, + AutoSizeAxes = Axes.Both, + } + }, + }, + } }, } }, }; } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + void fontPinkColour(SpriteText t) => t.Colour = colour.PinkLighter; + + supportLinkText.AddText("Support further development of osu! and ", fontPinkColour); + supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => + { + t.Colour = colour.PinkDark; + t.Font = t.Font.With(weight: FontWeight.Bold); + }); + supportLinkText.AddText(" today!", fontPinkColour); + + supportNoteText.AddText(new OsuSpriteText + { + Text = ChangelogStrings.SupportText2, + Colour = colour.PinkLighter, + }); + } } } From 49de8ce1df4254c30d8d0de05c2298c10523f56a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 13:53:06 +0700 Subject: [PATCH 114/961] fix up some layouting --- .../Changelog/ChangelogSupporterPromo.cs | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index ba5cac731b..b90e158f58 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -19,6 +19,8 @@ namespace osu.Game.Overlays.Changelog { public class ChangelogSupporterPromo : CompositeDrawable { + private const float image_width = 164; + private readonly LinkFlowContainer supportLinkText; private readonly TextFlowContainer supportNoteText; @@ -54,12 +56,11 @@ namespace osu.Game.Overlays.Changelog RelativeSizeAxes = Axes.Both, Colour = Color4.Black.Opacity(0.3f), }, - new FillFlowContainer + new Container { RelativeSizeAxes = Axes.X, Height = 200, Padding = new MarginPadding { Horizontal = 75 }, - Direction = FillDirection.Horizontal, Children = new Drawable[] { new FillFlowContainer @@ -69,6 +70,7 @@ namespace osu.Game.Overlays.Changelog Direction = FillDirection.Vertical, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, + Padding = new MarginPadding { Right = 50 + image_width }, Children = new Drawable[] { new OsuSpriteText @@ -82,7 +84,8 @@ namespace osu.Game.Overlays.Changelog t.Font = t.Font.With(size: 17.5f); }) { - AutoSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, }, supportNoteText = new TextFlowContainer(t => { @@ -90,10 +93,18 @@ namespace osu.Game.Overlays.Changelog }) { Margin = new MarginPadding { Top = 10 }, - AutoSizeAxes = Axes.Both, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, } }, }, + new Container + { + RelativeSizeAxes = Axes.Y, + Width = image_width, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + } } }, } @@ -114,11 +125,7 @@ namespace osu.Game.Overlays.Changelog }); supportLinkText.AddText(" today!", fontPinkColour); - supportNoteText.AddText(new OsuSpriteText - { - Text = ChangelogStrings.SupportText2, - Colour = colour.PinkLighter, - }); + supportNoteText.AddText("Not only will you help speed development, but you will also get some extra features and customisations!", fontPinkColour); } } } From b3fbf52571a0ded416210174d901d61bdeb0a218 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 14:07:20 +0700 Subject: [PATCH 115/961] add pippi and heart texture --- .../Changelog/ChangelogSupporterPromo.cs | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index b90e158f58..03373c4810 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -19,10 +20,11 @@ namespace osu.Game.Overlays.Changelog { public class ChangelogSupporterPromo : CompositeDrawable { - private const float image_width = 164; + private const float image_container_width = 164; private readonly LinkFlowContainer supportLinkText; private readonly TextFlowContainer supportNoteText; + private readonly Container imageContainer; public ChangelogSupporterPromo() { @@ -70,7 +72,7 @@ namespace osu.Game.Overlays.Changelog Direction = FillDirection.Vertical, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - Padding = new MarginPadding { Right = 50 + image_width }, + Padding = new MarginPadding { Right = 50 + image_container_width }, Children = new Drawable[] { new OsuSpriteText @@ -98,10 +100,10 @@ namespace osu.Game.Overlays.Changelog } }, }, - new Container + imageContainer = new Container { RelativeSizeAxes = Axes.Y, - Width = image_width, + Width = image_container_width, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, } @@ -113,7 +115,7 @@ namespace osu.Game.Overlays.Changelog } [BackgroundDependencyLoader] - private void load(OsuColour colour) + private void load(OsuColour colour, TextureStore textures) { void fontPinkColour(SpriteText t) => t.Colour = colour.PinkLighter; @@ -126,6 +128,27 @@ namespace osu.Game.Overlays.Changelog supportLinkText.AddText(" today!", fontPinkColour); supportNoteText.AddText("Not only will you help speed development, but you will also get some extra features and customisations!", fontPinkColour); + + imageContainer.Children = new Drawable[] + { + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + Texture = textures.Get(@"Online/supporter-pippi"), + }, + new Sprite + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Width = 75, + Height = 75, + Margin = new MarginPadding { Top = 70 }, + Texture = textures.Get(@"Online/supporter-heart"), + }, + }; } } } From f7a02219b80e528c90ca49283d6647599a74f81b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 14:23:15 +0700 Subject: [PATCH 116/961] fix font size description --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 03373c4810..f5638293bb 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -78,12 +78,12 @@ namespace osu.Game.Overlays.Changelog new OsuSpriteText { Text = ChangelogStrings.SupportHeading, - Font = OsuFont.GetFont(size: 22, weight: FontWeight.Light), + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), Margin = new MarginPadding { Bottom = 20 }, }, supportLinkText = new LinkFlowContainer(t => { - t.Font = t.Font.With(size: 17.5f); + t.Font = t.Font.With(size: 14); }) { RelativeSizeAxes = Axes.X, @@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Changelog }, supportNoteText = new TextFlowContainer(t => { - t.Font = t.Font.With(size: 15); + t.Font = t.Font.With(size: 12); }) { Margin = new MarginPadding { Top = 10 }, From 3fb2ca4f4a96acea47b9c17b2713afbec0d576fa Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 14:55:57 +0700 Subject: [PATCH 117/961] add border bottom --- osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 25d8eaf0db..1f1a4a43de 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -72,6 +72,12 @@ namespace osu.Game.Overlays.Changelog Margin = new MarginPadding { Top = 30 }, }, new ChangelogSupporterPromo(), + new Box + { + RelativeSizeAxes = Axes.X, + Height = 2, + Colour = colourProvider.Background6, + }, comments = new CommentsContainer() }; From 93408c636bbdd7b8bb5c92b3731c919d0687d620 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 14:56:54 +0700 Subject: [PATCH 118/961] hide supporter promo section for supporter --- osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs index 1f1a4a43de..93486274fc 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSingleBuild.cs @@ -71,12 +71,16 @@ namespace osu.Game.Overlays.Changelog Colour = colourProvider.Background6, Margin = new MarginPadding { Top = 30 }, }, - new ChangelogSupporterPromo(), + new ChangelogSupporterPromo + { + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, + }, new Box { RelativeSizeAxes = Axes.X, Height = 2, Colour = colourProvider.Background6, + Alpha = api.LocalUser.Value.IsSupporter ? 0 : 1, }, comments = new CommentsContainer() }; From 595763ae3453d1fbb979a299798809cf672e801c Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Tue, 10 Aug 2021 14:58:11 +0700 Subject: [PATCH 119/961] add test case for supporter and non supporter --- osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 8818ac75b1..159eb9912c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using Humanizer; using NUnit.Framework; +using osu.Framework.Testing; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -95,9 +96,11 @@ namespace osu.Game.Tests.Visual.Online AddAssert(@"no stream selected", () => changelog.Header.Streams.Current.Value == null); } - [Test] - public void ShowWithBuild() + [TestCase(false)] + [TestCase(true)] + public void ShowWithBuild(bool isSupporter) { + AddStep(@"set supporter", () => dummyAPI.LocalUser.Value.IsSupporter = isSupporter); showBuild(() => new APIChangelogBuild { Version = "2018.712.0", @@ -155,6 +158,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0); AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0"); AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 5); + AddAssert(@"supporter promo showed", () => changelog.ChildrenOfType().First().Alpha == (isSupporter ? 0 : 1)); } [Test] From 53d03745e046327870484b4ea38122aef357c68e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Aug 2021 17:48:47 +0900 Subject: [PATCH 120/961] Remove unused test scene --- .../Multiplayer/TestMultiplayerGameplay.cs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs deleted file mode 100644 index 4b75121575..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestMultiplayerGameplay.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Linq; -using NUnit.Framework; -using osu.Game.Screens.OnlinePlay.Multiplayer; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestMultiplayerGameplay : MultiplayerTestScene - { - [Test] - public void TestBasic() - { - AddStep("load screen", () => - LoadScreen(new MultiplayerPlayer(Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.Select(u => u.UserID).ToArray()))); - } - } -} From a503274e1d79e40bea8a85e9c4e8f45529822b61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 10 Aug 2021 18:39:20 +0900 Subject: [PATCH 121/961] Pass through `MultiplayerRoomUser`s instead of `int`s to avoid re-retrieval --- .../TestSceneMultiSpectatorLeaderboard.cs | 3 +- .../TestSceneMultiSpectatorScreen.cs | 17 +++++----- ...TestSceneMultiplayerGameplayLeaderboard.cs | 2 +- ...ceneMultiplayerGameplayLeaderboardTeams.cs | 2 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 6 ++-- .../Multiplayer/MultiplayerPlayer.cs | 10 +++--- .../Spectate/MultiSpectatorLeaderboard.cs | 4 +-- .../Spectate/MultiSpectatorScreen.cs | 19 +++++++---- .../HUD/MultiplayerGameplayLeaderboard.cs | 33 +++++++++---------- osu.Game/Screens/Spectate/SpectatorScreen.cs | 14 ++++---- 10 files changed, 59 insertions(+), 51 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs index 22543b7b26..ade24b8740 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorLeaderboard.cs @@ -6,6 +6,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Testing; using osu.Framework.Timing; +using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play.HUD; @@ -45,7 +46,7 @@ namespace osu.Game.Tests.Visual.Multiplayer var scoreProcessor = new OsuScoreProcessor(); scoreProcessor.ApplyBeatmap(playable); - LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(scoreProcessor, clocks.Keys.ToArray()) { Expanded = { Value = true } }, Add); + LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(scoreProcessor, clocks.Keys.Select(id => new MultiplayerRoomUser(id)).ToArray()) { Expanded = { Value = true } }, Add); }); AddUntilStep("wait for load", () => leaderboard.IsLoaded); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 116349c71e..3118a23fd5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Rulesets.UI; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; @@ -27,7 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private MultiSpectatorScreen spectatorScreen; - private readonly List playingUserIds = new List(); + private readonly List playingUsers = new List(); private BeatmapSetInfo importedSet; private BeatmapInfo importedBeatmap; @@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [SetUp] - public new void Setup() => Schedule(() => playingUserIds.Clear()); + public new void Setup() => Schedule(() => playingUsers.Clear()); [Test] public void TestDelayedStart() @@ -52,8 +53,8 @@ namespace osu.Game.Tests.Visual.Multiplayer OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true); OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true); - playingUserIds.Add(PLAYER_1_ID); - playingUserIds.Add(PLAYER_2_ID); + playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID)); + playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID)); }); loadSpectateScreen(false); @@ -99,8 +100,8 @@ namespace osu.Game.Tests.Visual.Multiplayer SpectatorClient.StartPlay(PLAYER_1_ID, importedBeatmapId); SpectatorClient.StartPlay(PLAYER_2_ID, importedBeatmapId); - playingUserIds.Add(PLAYER_1_ID); - playingUserIds.Add(PLAYER_2_ID); + playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID)); + playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID)); }); loadSpectateScreen(); @@ -287,7 +288,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Beatmap.Value = beatmapManager.GetWorkingBeatmap(importedBeatmap); Ruleset.Value = importedBeatmap.Ruleset; - LoadScreen(spectatorScreen = new MultiSpectatorScreen(playingUserIds.ToArray())); + LoadScreen(spectatorScreen = new MultiSpectatorScreen(playingUsers.ToArray())); }); AddUntilStep("wait for screen load", () => spectatorScreen.LoadState == LoadState.Loaded && (!waitForPlayerLoad || spectatorScreen.AllPlayersLoaded)); @@ -302,7 +303,7 @@ namespace osu.Game.Tests.Visual.Multiplayer OnlinePlayDependencies.Client.AddUser(new User { Id = id }, true); SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId); - playingUserIds.Add(id); + playingUsers.Add(new MultiplayerRoomUser(id)); } }); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 8121492a0b..0997de478b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -66,7 +66,7 @@ namespace osu.Game.Tests.Visual.Multiplayer scoreProcessor.ApplyBeatmap(playable); - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, users.ToArray()) + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index d363c6eed4..274c9ea4b2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -75,7 +75,7 @@ namespace osu.Game.Tests.Visual.Multiplayer scoreProcessor.ApplyBeatmap(playable); - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, users.ToArray()) + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 561fa220c8..9fa19aaf21 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -475,16 +475,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override Screen CreateGameplayScreen() { Debug.Assert(client.LocalUser != null); + Debug.Assert(client.Room != null); int[] userIds = client.CurrentMatchPlayingUserIds.ToArray(); + MultiplayerRoomUser[] users = userIds.Select(id => client.Room.Users.First(u => u.UserID == id)).ToArray(); switch (client.LocalUser.State) { case MultiplayerUserState.Spectating: - return new MultiSpectatorScreen(userIds); + return new MultiSpectatorScreen(users.Take(PlayerGrid.MAX_PLAYERS).ToArray()); default: - return new PlayerLoader(() => new MultiplayerPlayer(SelectedItem.Value, userIds)); + return new PlayerLoader(() => new MultiplayerPlayer(SelectedItem.Value, users)); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 0ff7d70c11..3ba7b8b982 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -37,7 +37,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private MultiplayerGameplayLeaderboard leaderboard; - private readonly int[] userIds; + private readonly MultiplayerRoomUser[] users; private LoadingLayer loadingDisplay; private FillFlowContainer leaderboardFlow; @@ -46,8 +46,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// Construct a multiplayer player. /// /// The playlist item to be played. - /// The users which are participating in this game. - public MultiplayerPlayer(PlaylistItem playlistItem, int[] userIds) + /// The users which are participating in this game. + public MultiplayerPlayer(PlaylistItem playlistItem, MultiplayerRoomUser[] users) : base(playlistItem, new PlayerConfiguration { AllowPause = false, @@ -55,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer AllowSkipping = false, }) { - this.userIds = userIds; + this.users = users; } [BackgroundDependencyLoader] @@ -71,7 +71,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }); // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, userIds), l => + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(ScoreProcessor, users), l => { if (!LoadedBeatmapSuccessfully) return; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs index 95f9fa27f1..1614828a78 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorLeaderboard.cs @@ -12,8 +12,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { public class MultiSpectatorLeaderboard : MultiplayerGameplayLeaderboard { - public MultiSpectatorLeaderboard([NotNull] ScoreProcessor scoreProcessor, int[] userIds) - : base(scoreProcessor, userIds) + public MultiSpectatorLeaderboard([NotNull] ScoreProcessor scoreProcessor, MultiplayerRoomUser[] users) + : base(scoreProcessor, users) { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 9923c42583..f77303eec7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -46,14 +46,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private PlayerArea currentAudioSource; private bool canStartMasterClock; + private readonly MultiplayerRoomUser[] users; + /// /// Creates a new . /// - /// The players to spectate. - public MultiSpectatorScreen(int[] userIds) - : base(userIds.Take(PlayerGrid.MAX_PLAYERS).ToArray()) + /// The players to spectate. + public MultiSpectatorScreen(MultiplayerRoomUser[] users) + : base(users.Select(u => u.UserID).ToArray()) { - instances = new PlayerArea[UserIds.Count]; + // todo: this is a bit ugly, but not sure on a better way to handle. + this.users = users; + + instances = new PlayerArea[Users.Count]; } [BackgroundDependencyLoader] @@ -105,9 +110,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate }) }; - for (int i = 0; i < UserIds.Count; i++) + for (int i = 0; i < Users.Count; i++) { - grid.Add(instances[i] = new PlayerArea(UserIds[i], masterClockContainer.GameplayClock)); + grid.Add(instances[i] = new PlayerArea(Users[i], masterClockContainer.GameplayClock)); syncManager.AddPlayerClock(instances[i].GameplayClock); } @@ -116,7 +121,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate var scoreProcessor = Ruleset.Value.CreateInstance().CreateScoreProcessor(); scoreProcessor.ApplyBeatmap(playableBeatmap); - LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(scoreProcessor, UserIds.ToArray()) + LoadComponentAsync(leaderboard = new MultiSpectatorLeaderboard(scoreProcessor, users) { Expanded = { Value = true }, Anchor = Anchor.CentreLeft, diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 013d266ac2..3f9258930e 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -41,23 +41,24 @@ namespace osu.Game.Screens.Play.HUD private UserLookupCache userLookupCache { get; set; } private readonly ScoreProcessor scoreProcessor; - private readonly IBindableList playingUsers; + private readonly MultiplayerRoomUser[] playingUsers; private Bindable scoringMode; + private readonly IBindableList playingUserIds = new BindableList(); + private bool hasTeams => TeamScores.Count > 0; /// /// Construct a new leaderboard. /// /// A score processor instance to handle score calculation for scores of users in the match. - /// IDs of all users in this match. - public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor, int[] userIds) + /// IDs of all users in this match. + public MultiplayerGameplayLeaderboard(ScoreProcessor scoreProcessor, MultiplayerRoomUser[] users) { // todo: this will eventually need to be created per user to support different mod combinations. this.scoreProcessor = scoreProcessor; - // todo: this will likely be passed in as User instances. - playingUsers = new BindableList(userIds); + playingUsers = users; } [BackgroundDependencyLoader] @@ -65,19 +66,17 @@ namespace osu.Game.Screens.Play.HUD { scoringMode = config.GetBindable(OsuSetting.ScoreDisplayMode); - foreach (var userId in playingUsers) + foreach (var user in playingUsers) { - var user = multiplayerClient.Room?.Users.FirstOrDefault(u => u.UserID == userId); - var trackedUser = CreateUserData(user, scoreProcessor); trackedUser.ScoringMode.BindTo(scoringMode); - UserScores[userId] = trackedUser; + UserScores[user.UserID] = trackedUser; if (trackedUser.Team is int team && !TeamScores.ContainsKey(team)) TeamScores.Add(team, new BindableInt()); } - userLookupCache.GetUsersAsync(playingUsers.ToArray()).ContinueWith(users => Schedule(() => + userLookupCache.GetUsersAsync(playingUsers.Select(u => u.UserID).ToArray()).ContinueWith(users => Schedule(() => { foreach (var user in users.Result) { @@ -100,18 +99,18 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); // BindableList handles binding in a really bad way (Clear then AddRange) so we need to do this manually.. - foreach (int userId in playingUsers) + foreach (var user in playingUsers) { - spectatorClient.WatchUser(userId); + spectatorClient.WatchUser(user.UserID); - if (!multiplayerClient.CurrentMatchPlayingUserIds.Contains(userId)) - usersChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new[] { userId })); + if (!multiplayerClient.CurrentMatchPlayingUserIds.Contains(user.UserID)) + usersChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new[] { user.UserID })); } // bind here is to support players leaving the match. // new players are not supported. - playingUsers.BindTo(multiplayerClient.CurrentMatchPlayingUserIds); - playingUsers.BindCollectionChanged(usersChanged); + playingUserIds.BindTo(multiplayerClient.CurrentMatchPlayingUserIds); + playingUserIds.BindCollectionChanged(usersChanged); // this leaderboard should be guaranteed to be completely loaded before the gameplay starts (is a prerequisite in MultiplayerPlayer). spectatorClient.OnNewFrames += handleIncomingFrames; @@ -197,7 +196,7 @@ namespace osu.Game.Screens.Play.HUD { foreach (var user in playingUsers) { - spectatorClient.StopWatchingUser(user); + spectatorClient.StopWatchingUser(user.UserID); } spectatorClient.OnNewFrames -= handleIncomingFrames; diff --git a/osu.Game/Screens/Spectate/SpectatorScreen.cs b/osu.Game/Screens/Spectate/SpectatorScreen.cs index b6eafe496f..f0a68ea078 100644 --- a/osu.Game/Screens/Spectate/SpectatorScreen.cs +++ b/osu.Game/Screens/Spectate/SpectatorScreen.cs @@ -24,9 +24,9 @@ namespace osu.Game.Screens.Spectate /// public abstract class SpectatorScreen : OsuScreen { - protected IReadOnlyList UserIds => userIds; + protected IReadOnlyList Users => users; - private readonly List userIds = new List(); + private readonly List users = new List(); [Resolved] private BeatmapManager beatmaps { get; set; } @@ -50,17 +50,17 @@ namespace osu.Game.Screens.Spectate /// /// Creates a new . /// - /// The users to spectate. - protected SpectatorScreen(params int[] userIds) + /// The users to spectate. + protected SpectatorScreen(params int[] users) { - this.userIds.AddRange(userIds); + this.users.AddRange(users); } protected override void LoadComplete() { base.LoadComplete(); - userLookupCache.GetUsersAsync(userIds.ToArray()).ContinueWith(users => Schedule(() => + userLookupCache.GetUsersAsync(users.ToArray()).ContinueWith(users => Schedule(() => { foreach (var u in users.Result) { @@ -207,7 +207,7 @@ namespace osu.Game.Screens.Spectate { onUserStateRemoved(userId); - userIds.Remove(userId); + users.Remove(userId); userMap.Remove(userId); spectatorClient.StopWatchingUser(userId); From 4268e4d75028d5ca43cf9786bb0a5efdcfb950a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 7 Aug 2021 14:19:05 +0200 Subject: [PATCH 122/961] Fix nested menus layering close samples if multiple menu levels are closed --- .../Cursor/OsuContextMenuContainer.cs | 9 +++++ .../Graphics/UserInterface/OsuContextMenu.cs | 29 +++++---------- .../UserInterface/OsuContextMenuSamples.cs | 35 +++++++++++++++++++ 3 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs diff --git a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs index e64d2d98f4..171ad4ee65 100644 --- a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; @@ -9,6 +10,14 @@ namespace osu.Game.Graphics.Cursor { public class OsuContextMenuContainer : ContextMenuContainer { + [Cached] + private OsuContextMenuSamples samples = new OsuContextMenuSamples(); + + public OsuContextMenuContainer() + { + AddInternal(samples); + } + protected override Menu CreateMenu() => new OsuContextMenu(true); } } diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index 7cf8b3eca8..cf201b18b4 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -4,8 +4,6 @@ using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; @@ -16,16 +14,15 @@ namespace osu.Game.Graphics.UserInterface public class OsuContextMenu : OsuMenu { private const int fade_duration = 250; - private Sample sampleOpen; - private Sample sampleClose; - private Sample sampleClick; + + [Resolved] + private OsuContextMenuSamples samples { get; set; } // todo: this shouldn't be required after https://github.com/ppy/osu-framework/issues/4519 is fixed. private bool wasOpened; private readonly bool playClickSample; - private readonly Menu parentMenu; - public OsuContextMenu(bool playClickSample = false, Menu parentMenu = null) + public OsuContextMenu(bool playClickSample = false) : base(Direction.Vertical) { MaskingContainer.CornerRadius = 5; @@ -41,16 +38,12 @@ namespace osu.Game.Graphics.UserInterface MaxHeight = 250; this.playClickSample = playClickSample; - this.parentMenu = parentMenu; } [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audio) { BackgroundColour = colours.ContextMenuGray; - sampleClick = audio.Samples.Get($"UI/{HoverSampleSet.Default.GetDescription()}-select"); - sampleOpen = audio.Samples.Get(@"UI/dropdown-open"); - sampleClose = audio.Samples.Get(@"UI/dropdown-close"); } protected override void AnimateOpen() @@ -58,10 +51,10 @@ namespace osu.Game.Graphics.UserInterface this.FadeIn(fade_duration, Easing.OutQuint); if (playClickSample) - sampleClick?.Play(); + samples.PlayClickSample(); if (!wasOpened) - sampleOpen?.Play(); + samples.PlayOpenSample(); wasOpened = true; } @@ -70,18 +63,12 @@ namespace osu.Game.Graphics.UserInterface { this.FadeOut(fade_duration, Easing.OutQuint); - if (parentMenu?.State == MenuState.Closed) - { - wasOpened = false; - return; - } - if (wasOpened) - sampleClose?.Play(); + samples.PlayCloseSample(); wasOpened = false; } - protected override Menu CreateSubMenu() => new OsuContextMenu(false, this); + protected override Menu CreateSubMenu() => new OsuContextMenu(); } } diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs b/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs new file mode 100644 index 0000000000..d67ea499e5 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/OsuContextMenuSamples.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Extensions; +using osu.Framework.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public class OsuContextMenuSamples : Component + { + private Sample sampleClick; + private Sample sampleOpen; + private Sample sampleClose; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, AudioManager audio) + { + sampleClick = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); + sampleOpen = audio.Samples.Get(@"UI/dropdown-open"); + sampleClose = audio.Samples.Get(@"UI/dropdown-close"); + } + + public void PlayClickSample() => Scheduler.AddOnce(playClickSample); + private void playClickSample() => sampleClick.Play(); + + public void PlayOpenSample() => Scheduler.AddOnce(playOpenSample); + private void playOpenSample() => sampleOpen.Play(); + + public void PlayCloseSample() => Scheduler.AddOnce(playCloseSample); + private void playCloseSample() => sampleClose.Play(); + } +} From f2f84a2e239ca8f03a899a81c6ec551c403170ba Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 11 Aug 2021 12:11:39 +0700 Subject: [PATCH 123/961] wait for content to load in test --- osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs index 159eb9912c..8f000afb91 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs @@ -158,6 +158,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep(@"wait for streams", () => changelog.Streams?.Count > 0); AddAssert(@"correct build displayed", () => changelog.Current.Value.Version == "2018.712.0"); AddAssert(@"correct stream selected", () => changelog.Header.Streams.Current.Value.Id == 5); + AddUntilStep(@"wait for content load", () => changelog.ChildrenOfType().Any()); AddAssert(@"supporter promo showed", () => changelog.ChildrenOfType().First().Alpha == (isSupporter ? 0 : 1)); } From cf82bca09c56eed50dd4dc7b8e97e80af76825d2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 14:44:13 +0900 Subject: [PATCH 124/961] Change logic to only handle the case of exactly two teams --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index f77303eec7..2846fbec29 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -133,7 +133,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate leaderboardContainer.Add(leaderboard); - if (leaderboard.TeamScores.Count >= 2) + if (leaderboard.TeamScores.Count == 2) { LoadComponentAsync(new MatchScoreDisplay { From ee3b373e8a0db22c0119d1822ca2db468ba586fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 14:48:37 +0900 Subject: [PATCH 125/961] Correctly handle tied scores --- .../Screens/Play/HUD/MatchScoreDisplay.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index 837d8bfde7..c77b872786 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -112,11 +112,23 @@ namespace osu.Game.Screens.Play.HUD Score1Text.Current.Value = Team1Score.Value; Score2Text.Current.Value = Team2Score.Value; - var winningText = Team1Score.Value > Team2Score.Value ? Score1Text : Score2Text; - var losingText = Team1Score.Value <= Team2Score.Value ? Score1Text : Score2Text; + int comparison = Team1Score.Value.CompareTo(Team2Score.Value); - winningText.Winning = true; - losingText.Winning = false; + if (comparison > 0) + { + Score1Text.Winning = true; + Score2Text.Winning = false; + } + else if (comparison < 0) + { + Score1Text.Winning = false; + Score2Text.Winning = true; + } + else + { + Score1Text.Winning = false; + Score2Text.Winning = false; + } var winningBar = Team1Score.Value > Team2Score.Value ? score1Bar : score2Bar; var losingBar = Team1Score.Value <= Team2Score.Value ? score1Bar : score2Bar; From fb7ed08bab60c42b68bb3d3816259cd8bbeb8c70 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Wed, 11 Aug 2021 12:49:22 +0700 Subject: [PATCH 126/961] move text creation to load method --- .../Changelog/ChangelogSupporterPromo.cs | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index f5638293bb..c0d78cc887 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -22,8 +22,7 @@ namespace osu.Game.Overlays.Changelog { private const float image_container_width = 164; - private readonly LinkFlowContainer supportLinkText; - private readonly TextFlowContainer supportNoteText; + private readonly FillFlowContainer textContainer; private readonly Container imageContainer; public ChangelogSupporterPromo() @@ -65,7 +64,7 @@ namespace osu.Game.Overlays.Changelog Padding = new MarginPadding { Horizontal = 75 }, Children = new Drawable[] { - new FillFlowContainer + textContainer = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -73,32 +72,6 @@ namespace osu.Game.Overlays.Changelog Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Padding = new MarginPadding { Right = 50 + image_container_width }, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = ChangelogStrings.SupportHeading, - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), - Margin = new MarginPadding { Bottom = 20 }, - }, - supportLinkText = new LinkFlowContainer(t => - { - t.Font = t.Font.With(size: 14); - }) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - supportNoteText = new TextFlowContainer(t => - { - t.Font = t.Font.With(size: 12); - }) - { - Margin = new MarginPadding { Top = 10 }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - }, }, imageContainer = new Container { @@ -117,17 +90,44 @@ namespace osu.Game.Overlays.Changelog [BackgroundDependencyLoader] private void load(OsuColour colour, TextureStore textures) { - void fontPinkColour(SpriteText t) => t.Colour = colour.PinkLighter; + LinkFlowContainer supportLinkText; + textContainer.Children = new Drawable[] + { + new OsuSpriteText + { + Text = ChangelogStrings.SupportHeading, + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), + Margin = new MarginPadding { Bottom = 20 }, + }, + supportLinkText = new LinkFlowContainer(t => + { + t.Font = t.Font.With(size: 14); + t.Colour = colour.PinkLighter; + }) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + new TextFlowContainer(t => + { + t.Font = t.Font.With(size: 12); + t.Colour = colour.PinkLighter; + }) + { + Text = "Not only will you help speed development, but you will also get some extra features and customisations!", + Margin = new MarginPadding { Top = 10 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }; - supportLinkText.AddText("Support further development of osu! and ", fontPinkColour); + supportLinkText.AddText("Support further development of osu! and "); supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => { t.Colour = colour.PinkDark; t.Font = t.Font.With(weight: FontWeight.Bold); }); - supportLinkText.AddText(" today!", fontPinkColour); - - supportNoteText.AddText("Not only will you help speed development, but you will also get some extra features and customisations!", fontPinkColour); + supportLinkText.AddText(" today!"); imageContainer.Children = new Drawable[] { From 735c5085ddd29088ba5ae1a9fd817b1f335995d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 14:43:01 +0900 Subject: [PATCH 127/961] Fix match score display not doing an initial value update --- osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index c77b872786..607d08b8ed 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -104,7 +104,7 @@ namespace osu.Game.Screens.Play.HUD base.LoadComplete(); Team1Score.BindValueChanged(_ => updateScores()); - Team2Score.BindValueChanged(_ => updateScores()); + Team2Score.BindValueChanged(_ => updateScores(), true); } private void updateScores() From c376e652a4abdd44cc2e22ea06a45cd356e22b45 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 14:43:16 +0900 Subject: [PATCH 128/961] Convey and show team scores at the multiplayer results screen --- .../TestSceneMultiplayerTeamResults.cs | 88 +++++++++++++++++++ .../Multiplayer/MultiplayerPlayer.cs | 2 +- .../Multiplayer/MultiplayerResultsScreen.cs | 23 ++++- 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs new file mode 100644 index 0000000000..2b04955d5e --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -0,0 +1,88 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Osu; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMultiplayerTeamResults : ScreenTestScene + { + [Test] + public void TestDisplayWithTeams() + { + AddStep("show results screen", () => + { + var rulesetInfo = new OsuRuleset().RulesetInfo; + var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo; + + var score = new ScoreInfo + { + Rank = ScoreRank.B, + TotalScore = 987654, + Accuracy = 0.8, + MaxCombo = 500, + Combo = 250, + Beatmap = beatmapInfo, + User = new User { Username = "Test user" }, + Date = DateTimeOffset.Now, + OnlineScoreID = 12345, + Ruleset = rulesetInfo, + }; + + PlaylistItem playlistItem = new PlaylistItem + { + BeatmapID = beatmapInfo.ID, + }; + + SortedDictionary teamScores = new SortedDictionary + { + { 0, new BindableInt(7483253) }, + { 1, new BindableInt(1048576) } + }; + + Stack.Push(new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + }); + } + + [Test] + public void TestDisplayWithoutTeams() + { + AddStep("show results screen", () => + { + var rulesetInfo = new OsuRuleset().RulesetInfo; + var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo; + + var score = new ScoreInfo + { + Rank = ScoreRank.B, + TotalScore = 987654, + Accuracy = 0.8, + MaxCombo = 500, + Combo = 250, + Beatmap = beatmapInfo, + User = new User { Username = "Test user" }, + Date = DateTimeOffset.Now, + OnlineScoreID = 12345, + Ruleset = rulesetInfo, + }; + + PlaylistItem playlistItem = new PlaylistItem + { + BeatmapID = beatmapInfo.ID, + }; + + SortedDictionary teamScores = new SortedDictionary(); + + Stack.Push(new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + }); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 3ba7b8b982..3c892d03df 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -181,7 +181,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override ResultsScreen CreateResults(ScoreInfo score) { Debug.Assert(RoomId.Value != null); - return new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem); + return new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem, leaderboard.TeamScores); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 140b3c45d8..66de572b77 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -1,17 +1,38 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; +using osu.Game.Screens.Play.HUD; namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerResultsScreen : PlaylistsResultsScreen { - public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem) + private readonly SortedDictionary teamScores; + + public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, SortedDictionary teamScores) : base(score, roomId, playlistItem, false, false) { + this.teamScores = teamScores; + } + + [BackgroundDependencyLoader] + private void load() + { + if (teamScores.Count == 2) + { + LoadComponentAsync(new MatchScoreDisplay + { + Team1Score = { BindTarget = teamScores.First().Value }, + Team2Score = { BindTarget = teamScores.Last().Value }, + }, AddInternal); + } } } } From 430a0e496caf02df211f55fcb0fee7fdb0bf5759 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 15:32:10 +0900 Subject: [PATCH 129/961] Add winner text --- .../MultiplayerResultsScreenStrings.cs | 19 +++++ .../Multiplayer/MultiplayerResultsScreen.cs | 72 +++++++++++++++++-- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Localisation/MultiplayerResultsScreenStrings.cs diff --git a/osu.Game/Localisation/MultiplayerResultsScreenStrings.cs b/osu.Game/Localisation/MultiplayerResultsScreenStrings.cs new file mode 100644 index 0000000000..e586faba66 --- /dev/null +++ b/osu.Game/Localisation/MultiplayerResultsScreenStrings.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class MultiplayerResultsScreenStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.MultiplayerResultsScreen"; + + /// + /// "Team {0} wins!" + /// + public static LocalisableString TeamWins(string winner) => new TranslatableString(getKey(@"team_wins"), @"Team {0} wins!", winner); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 66de572b77..61bc66de45 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -5,10 +5,18 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play.HUD; +using osu.Game.Localisation; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -16,22 +24,78 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { private readonly SortedDictionary teamScores; + private Drawable winnerText; + public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, SortedDictionary teamScores) : base(score, roomId, playlistItem, false, false) { this.teamScores = teamScores; } + [Resolved] + private OsuColour colours { get; set; } + [BackgroundDependencyLoader] private void load() { if (teamScores.Count == 2) { - LoadComponentAsync(new MatchScoreDisplay + var redScore = teamScores.First().Value; + var blueScore = teamScores.Last().Value; + + // eventually this will be replaced by team names coming from the multiplayer match state. + string winner = redScore.Value > blueScore.Value ? @"Red" : @"Blue"; + + var winnerColour = redScore.Value > blueScore.Value ? colours.TeamColourRed : colours.TeamColourBlue; + + AddRangeInternal(new Drawable[] { - Team1Score = { BindTarget = teamScores.First().Value }, - Team2Score = { BindTarget = teamScores.Last().Value }, - }, AddInternal); + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new MatchScoreDisplay + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Team1Score = { BindTarget = redScore }, + Team2Score = { BindTarget = blueScore }, + }, + (winnerText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.Torus.With(size: 40, weight: FontWeight.Bold), + Text = MultiplayerResultsScreenStrings.TeamWins(winner) + }).WithEffect(new GlowEffect + { + Colour = winnerColour, + }).With(e => + { + e.Anchor = Anchor.TopCentre; + e.Origin = Anchor.TopCentre; + }) + } + }, + }); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + using (BeginDelayedSequence(300)) + { + winnerText.FadeInFromZero(600, Easing.InQuint); + + winnerText + .ScaleTo(10) + .ScaleTo(1, 600, Easing.InQuad) + .Then() + .ScaleTo(1.02f, 1600, Easing.OutQuint); } } } From a223f111cb43633f53be512e16215c13b4f90721 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 15:50:01 +0900 Subject: [PATCH 130/961] Move text to avoid overlapping the results panel --- .../Multiplayer/MultiplayerResultsScreen.cs | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 61bc66de45..0e4655e336 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -5,18 +5,16 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play.HUD; -using osu.Game.Localisation; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -50,35 +48,27 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer AddRangeInternal(new Drawable[] { - new FillFlowContainer + new MatchScoreDisplay { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new MatchScoreDisplay - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Team1Score = { BindTarget = redScore }, - Team2Score = { BindTarget = blueScore }, - }, - (winnerText = new OsuSpriteText - { - Alpha = 0, - Font = OsuFont.Torus.With(size: 40, weight: FontWeight.Bold), - Text = MultiplayerResultsScreenStrings.TeamWins(winner) - }).WithEffect(new GlowEffect - { - Colour = winnerColour, - }).With(e => - { - e.Anchor = Anchor.TopCentre; - e.Origin = Anchor.TopCentre; - }) - } + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Team1Score = { BindTarget = redScore }, + Team2Score = { BindTarget = blueScore }, }, + (winnerText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.Torus.With(size: 80, weight: FontWeight.Bold), + Text = MultiplayerResultsScreenStrings.TeamWins(winner), + Blending = BlendingParameters.Additive + }).WithEffect(new GlowEffect + { + Colour = winnerColour, + }).With(e => + { + e.Anchor = Anchor.Centre; + e.Origin = Anchor.Centre; + }) }); } } @@ -95,7 +85,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer .ScaleTo(10) .ScaleTo(1, 600, Easing.InQuad) .Then() - .ScaleTo(1.02f, 1600, Easing.OutQuint); + .ScaleTo(1.02f, 1600, Easing.OutQuint) + .FadeOut(5000, Easing.InQuad); } } } From f8683e2256d8e452da31d6429cdada61e92833b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 16:17:21 +0900 Subject: [PATCH 131/961] 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 8de516240f..454bb46059 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 59283084db..e6219fcb85 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index c8d3d150db..9904946363 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 0ffe740ca1dcce1e2c7fa276f96f523b004b0fed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 16:24:47 +0900 Subject: [PATCH 132/961] Bring back `TestSceneOsuGame` I marked this as headless to avoid it being "ungrouped", but it turns out this is quite useful to have around and I have searched for it on multiple occasions. --- osu.Game.Tests/Visual/{ => Navigation}/TestSceneOsuGame.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename osu.Game.Tests/Visual/{ => Navigation}/TestSceneOsuGame.cs (98%) diff --git a/osu.Game.Tests/Visual/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs similarity index 98% rename from osu.Game.Tests/Visual/TestSceneOsuGame.cs rename to osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index c52d846a68..26641214b1 100644 --- a/osu.Game.Tests/Visual/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Platform; -using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -30,10 +29,9 @@ using osu.Game.Skinning; using osu.Game.Utils; using osuTK.Graphics; -namespace osu.Game.Tests.Visual +namespace osu.Game.Tests.Visual.Navigation { [TestFixture] - [HeadlessTest] public class TestSceneOsuGame : OsuTestScene { private IReadOnlyList requiredGameDependencies => new[] From 3f067e3a8d20ed33d8ab8f7f9434b3da6377fcc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 16:59:42 +0900 Subject: [PATCH 133/961] Remove likely unnecessary score null check --- osu.Game/Screens/Play/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 1692975210..09eaf1c543 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -962,7 +962,7 @@ namespace osu.Game.Screens.Play screenSuspension?.Expire(); // if arriving here and the results screen preparation task hasn't run, it's safe to say the user has not completed the beatmap. - if (Score != null && prepareScoreForDisplayTask == null) + if (prepareScoreForDisplayTask == null) { Score.ScoreInfo.Passed = false; // potentially should be ScoreRank.F instead? this is the best alternative for now. From e8ad0fba75f8bf6482a1a60e8ec18019c7adc30f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 17:20:41 +0900 Subject: [PATCH 134/961] Add required server methods for kicking users --- osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs | 8 ++++++++ osu.Game/Online/Multiplayer/MultiplayerClient.cs | 2 ++ osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 8 ++++++++ .../Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 7 +++++++ 4 files changed, 25 insertions(+) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs index b26c4d8201..da637c229f 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerRoomServer.cs @@ -27,6 +27,14 @@ namespace osu.Game.Online.Multiplayer /// If the user is not in a room. Task TransferHost(int userId); + /// + /// As the host, kick another user from the room. + /// + /// The user to kick.. + /// A user other than the current host is attempting to kick a user. + /// If the user is not in a room. + Task KickUser(int userId); + /// /// As the host, update the settings of the currently joined room. /// diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index dafc737ba2..4607211cdf 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -293,6 +293,8 @@ namespace osu.Game.Online.Multiplayer public abstract Task TransferHost(int userId); + public abstract Task KickUser(int userId); + public abstract Task ChangeSettings(MultiplayerRoomSettings settings); public abstract Task ChangeState(MultiplayerUserState newState); diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 8b8d10ce4f..55477a9fc7 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -91,6 +91,14 @@ namespace osu.Game.Online.Multiplayer return connection.InvokeAsync(nameof(IMultiplayerServer.TransferHost), userId); } + public override Task KickUser(int userId) + { + if (!IsConnected.Value) + return Task.CompletedTask; + + return connection.InvokeAsync(nameof(IMultiplayerServer.KickUser), userId); + } + public override Task ChangeSettings(MultiplayerRoomSettings settings) { if (!IsConnected.Value) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index cffaea5c94..a28b4140ca 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -174,6 +174,13 @@ namespace osu.Game.Tests.Visual.Multiplayer public override Task TransferHost(int userId) => ((IMultiplayerClient)this).HostChanged(userId); + public override Task KickUser(int userId) + { + Debug.Assert(Room != null); + + return ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.UserID == userId)); + } + public override async Task ChangeSettings(MultiplayerRoomSettings settings) { Debug.Assert(Room != null); From 7aab8c32ecec37fe1c34e1f344bfd90eca3aa1ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 17:20:47 +0900 Subject: [PATCH 135/961] Add kick button and hook up logic --- .../Participants/ParticipantPanel.cs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 89431445d3..bfe99911b6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -42,6 +43,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private ModDisplay userModsDisplay; private StateDisplay userStateDisplay; + private IconButton kickButton; + public ParticipantPanel(MultiplayerRoomUser user) { User = user; @@ -64,7 +67,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { new Dimension(GridSizeMode.Absolute, 18), new Dimension(GridSizeMode.AutoSize), - new Dimension() + new Dimension(), + new Dimension(GridSizeMode.AutoSize), }, Content = new[] { @@ -157,7 +161,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants Margin = new MarginPadding { Right = 10 }, } } - } + }, + kickButton = new KickButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Margin = new MarginPadding(4), + Action = () => + { + Debug.Assert(user != null); + + Client.KickUser(user.Id); + } + }, }, } }; @@ -179,6 +196,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability); + if (Client.LocalUser != null && Room.Host?.Equals(Client.LocalUser) == true) + kickButton.FadeIn(fade_time); + else + kickButton.FadeOut(fade_time); + if (Room.Host?.Equals(User) == true) crown.FadeIn(fade_time); else @@ -219,5 +241,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants }; } } + + public class KickButton : IconButton + { + public KickButton() + { + Icon = FontAwesome.Solid.UserTimes; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IconHoverColour = colours.Red; + } + } } } From 50bda6023cf995258991598f8b02bc3ed9761767 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 17:31:37 +0900 Subject: [PATCH 136/961] Add test coverage --- .../TestSceneMultiplayerParticipantsList.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index 6526f7eea7..b2fca61530 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -155,6 +155,42 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("second user crown visible", () => this.ChildrenOfType().ElementAt(1).ChildrenOfType().First().Alpha == 1); } + [Test] + public void TestKickButtonOnlyPresentWhenHost() + { + AddStep("add user", () => Client.AddUser(new User + { + Id = 3, + Username = "Second", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + })); + + AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 2); + + AddStep("make second user host", () => Client.TransferHost(3)); + + AddUntilStep("kick buttons not visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 0); + + AddStep("make local user host again", () => Client.TransferHost(API.LocalUser.Value.Id)); + + AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 2); + } + + [Test] + public void TestKickButtonKicks() + { + AddStep("add user", () => Client.AddUser(new User + { + Id = 3, + Username = "Second", + CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", + })); + + AddStep("kick second user", () => this.ChildrenOfType().Last().TriggerClick()); + + AddAssert("second user kicked", () => Client.Room?.Users.Single().UserID == API.LocalUser.Value.Id); + } + [Test] public void TestManyUsers() { From bb51ebd0ef2c67dbe1978ac5edad128adc98c8e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 17:39:23 +0900 Subject: [PATCH 137/961] Don't show button on self --- .../Multiplayer/TestSceneMultiplayerParticipantsList.cs | 6 +++--- .../OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index b2fca61530..a3e6c8de3b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -165,7 +165,7 @@ namespace osu.Game.Tests.Visual.Multiplayer CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", })); - AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 2); + AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 1); AddStep("make second user host", () => Client.TransferHost(3)); @@ -173,7 +173,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("make local user host again", () => Client.TransferHost(API.LocalUser.Value.Id)); - AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 2); + AddUntilStep("kick buttons visible", () => this.ChildrenOfType().Count(d => d.IsPresent) == 1); } [Test] @@ -186,7 +186,7 @@ namespace osu.Game.Tests.Visual.Multiplayer CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg", })); - AddStep("kick second user", () => this.ChildrenOfType().Last().TriggerClick()); + AddStep("kick second user", () => this.ChildrenOfType().Single(d => d.IsPresent).TriggerClick()); AddAssert("second user kicked", () => Client.Room?.Users.Single().UserID == API.LocalUser.Value.Id); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index bfe99911b6..54baaceb36 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { base.OnRoomUpdated(); - if (Room == null) + if (Room == null || Client.LocalUser == null) return; const double fade_time = 50; @@ -196,7 +196,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants userStateDisplay.UpdateStatus(User.State, User.BeatmapAvailability); - if (Client.LocalUser != null && Room.Host?.Equals(Client.LocalUser) == true) + if (Client.IsHost && !User.Equals(Client.LocalUser)) kickButton.FadeIn(fade_time); else kickButton.FadeOut(fade_time); From d6352637d6e7ea99dbe02cbe1c920b7d14aa9a54 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 17:45:34 +0900 Subject: [PATCH 138/961] Also add tooltip and context menu item --- .../Multiplayer/Participants/ParticipantPanel.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 54baaceb36..1787480e1f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -233,10 +233,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants new OsuMenuItem("Give host", MenuItemType.Standard, () => { // Ensure the local user is still host. - if (Room.Host?.UserID != api.LocalUser.Value.Id) + if (!Client.IsHost) return; Client.TransferHost(targetUser); + }), + new OsuMenuItem("Kick", MenuItemType.Destructive, () => + { + // Ensure the local user is still host. + if (!Client.IsHost) + return; + + Client.KickUser(targetUser); }) }; } @@ -247,6 +255,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants public KickButton() { Icon = FontAwesome.Solid.UserTimes; + TooltipText = "Kick"; } [BackgroundDependencyLoader] From eb59f3c59188d7ca86e42143a9d9f45802fdda53 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Aug 2021 18:15:53 +0900 Subject: [PATCH 139/961] Revert "Buffer the entire star rating range to fix overlapping alpha" This reverts commit c680012523ff9f4a1e8ab10f788401a9f3b68986. --- .../Components/StarRatingRangeDisplay.cs | 57 +++++++++---------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 622643f5ea..01a21227df 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -33,41 +33,38 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - InternalChild = new BufferedContainer + InternalChildren = new Drawable[] { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] + new Container { - new Container + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 1, + Children = new[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Vertical = 1 }, - Children = new[] + minBackground = new Box { - minBackground = new Box - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f), - }, - maxBackground = new Box - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f), - }, - } - }, - new FillFlowContainer + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + }, + maxBackground = new Box + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - minDisplay = new StarRatingDisplay(default), - maxDisplay = new StarRatingDisplay(default) - } + minDisplay = new StarRatingDisplay(default), + maxDisplay = new StarRatingDisplay(default) } } }; From 4002a1606eaf8db60d40370d63f2caf3ee3880a6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 11 Aug 2021 18:20:39 +0900 Subject: [PATCH 140/961] Round star ratings before comparing --- .../Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 01a21227df..a27b27b8ad 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; @@ -86,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Components minDisplay.Current.Value = minDifficulty; maxDisplay.Current.Value = maxDifficulty; - maxDisplay.Alpha = Precision.AlmostEquals(minDifficulty.Stars, maxDifficulty.Stars) ? 0 : 1; + maxDisplay.Alpha = Precision.AlmostEquals(Math.Round(minDifficulty.Stars, 2), Math.Round(maxDifficulty.Stars, 2)) ? 0 : 1; minBackground.Colour = colours.ForStarDifficulty(minDifficulty.Stars); maxBackground.Colour = colours.ForStarDifficulty(maxDifficulty.Stars); From d9a4f018e65ce669a1fd329a3aa6880b5c94bdbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 18:26:36 +0900 Subject: [PATCH 141/961] Add event flow for receiving kick commands --- osu.Game/Online/Multiplayer/IMultiplayerClient.cs | 9 +++++++++ osu.Game/Online/Multiplayer/MultiplayerClient.cs | 6 ++++++ osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 1 + 3 files changed, 16 insertions(+) diff --git a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs index 064065ab00..8f16d22c4c 100644 --- a/osu.Game/Online/Multiplayer/IMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/IMultiplayerClient.cs @@ -31,6 +31,15 @@ namespace osu.Game.Online.Multiplayer /// The user. Task UserLeft(MultiplayerRoomUser user); + /// + /// Signals that a user has been kicked from the room. + /// + /// + /// This will also be sent to the user that was kicked. + /// + /// The user. + Task UserKicked(MultiplayerRoomUser user); + /// /// Signal that the host of the room has changed. /// diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 4607211cdf..7e964ed5fa 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -389,6 +389,12 @@ namespace osu.Game.Online.Multiplayer return Task.CompletedTask; } + Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user) + { + // TODO: also inform users of the kick operation. + return ((IMultiplayerClient)this).UserLeft(user); + } + Task IMultiplayerClient.HostChanged(int userId) { if (Room == null) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index 55477a9fc7..c38a648a6a 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -50,6 +50,7 @@ namespace osu.Game.Online.Multiplayer connection.On(nameof(IMultiplayerClient.RoomStateChanged), ((IMultiplayerClient)this).RoomStateChanged); connection.On(nameof(IMultiplayerClient.UserJoined), ((IMultiplayerClient)this).UserJoined); connection.On(nameof(IMultiplayerClient.UserLeft), ((IMultiplayerClient)this).UserLeft); + connection.On(nameof(IMultiplayerClient.UserKicked), ((IMultiplayerClient)this).UserKicked); connection.On(nameof(IMultiplayerClient.HostChanged), ((IMultiplayerClient)this).HostChanged); connection.On(nameof(IMultiplayerClient.SettingsChanged), ((IMultiplayerClient)this).SettingsChanged); connection.On(nameof(IMultiplayerClient.UserStateChanged), ((IMultiplayerClient)this).UserStateChanged); From 9b21ebd6d04410d2e5fcd363cf26b4ee88a0bfec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 18:31:04 +0900 Subject: [PATCH 142/961] Add client side handling on incoming kick --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 7e964ed5fa..57dbfbb507 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -190,7 +190,8 @@ namespace osu.Game.Online.Multiplayer return joinOrLeaveTaskChain.Add(async () => { await scheduledReset.ConfigureAwait(false); - await LeaveRoomInternal().ConfigureAwait(false); + if (Room != null) + await LeaveRoomInternal().ConfigureAwait(false); }); } @@ -391,6 +392,12 @@ namespace osu.Game.Online.Multiplayer Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user) { + if (LocalUser == null) + return Task.CompletedTask; + + if (user.Equals(LocalUser)) + LeaveRoom(); + // TODO: also inform users of the kick operation. return ((IMultiplayerClient)this).UserLeft(user); } From 31608a1bc6c4a691571967dd1e893a7ac4338ee9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 11 Aug 2021 19:56:25 +0900 Subject: [PATCH 143/961] Leave the match screen when kicked --- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 561fa220c8..57dde31b68 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -448,6 +448,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private void onRoomUpdated() { + // may happen if the client is kicked or otherwise removed from the room. + if (client.Room == null) + { + Schedule(this.Exit); + return; + } + Scheduler.AddOnce(UpdateMods); } From a1f50e39aa12d86456af684804c0894ec1ccf871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 25 Jul 2021 16:50:52 +0200 Subject: [PATCH 144/961] Add basic structure for skinning catch explosions --- .../TestSceneCatcherArea.cs | 1 + .../CatchSkinComponents.cs | 3 +- .../Skinning/Default/DefaultHitExplosion.cs | 145 ++++++++++++++++++ osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 121 ++------------- .../UI/HitExplosionContainer.cs | 3 + 5 files changed, 168 insertions(+), 105 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs index a3307c9224..6abfbdbe21 100644 --- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs +++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs @@ -40,6 +40,7 @@ namespace osu.Game.Rulesets.Catch.Tests { AddSliderStep("circle size", 0, 8, 5, createCatcher); AddToggleStep("hyper dash", t => this.ChildrenOfType().ForEach(area => area.ToggleHyperDash(t))); + AddToggleStep("toggle hit lighting", lighting => config.SetValue(OsuSetting.HitLighting, lighting)); AddStep("catch centered fruit", () => attemptCatch(new Fruit())); AddStep("catch many random fruit", () => diff --git a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs index e736d68740..371e901c69 100644 --- a/osu.Game.Rulesets.Catch/CatchSkinComponents.cs +++ b/osu.Game.Rulesets.Catch/CatchSkinComponents.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Catch Banana, Droplet, Catcher, - CatchComboCounter + CatchComboCounter, + HitExplosion } } diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs new file mode 100644 index 0000000000..41ba81d34c --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -0,0 +1,145 @@ +// 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.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Utils; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Rulesets.Catch.Skinning.Default +{ + public class DefaultHitExplosion : CompositeDrawable + { + [Resolved] + private Bindable entryBindable { get; set; } + + private CircularContainer largeFaint; + private CircularContainer smallFaint; + private CircularContainer directionalGlow1; + private CircularContainer directionalGlow2; + + [BackgroundDependencyLoader] + private void load() + { + Size = new Vector2(20); + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + + // scale roughly in-line with visual appearance of notes + const float initial_height = 10; + + InternalChildren = new Drawable[] + { + largeFaint = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Blending = BlendingParameters.Additive, + }, + smallFaint = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Blending = BlendingParameters.Additive, + }, + directionalGlow1 = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Size = new Vector2(0.01f, initial_height), + Blending = BlendingParameters.Additive, + }, + directionalGlow2 = new CircularContainer + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Masking = true, + Size = new Vector2(0.01f, initial_height), + Blending = BlendingParameters.Additive, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + entryBindable.BindValueChanged(entry => apply(entry.NewValue), true); + } + + private void apply(HitExplosionEntry entry) + { + if (entry == null) + return; + + X = entry.Position; + Scale = new Vector2(entry.Scale); + setColour(entry.ObjectColour); + + using (BeginAbsoluteSequence(entry.LifetimeStart)) + applyTransforms(entry.RNGSeed); + } + + private void applyTransforms(int randomSeed) + { + ClearTransforms(true); + + const double duration = 400; + + // we want our size to be very small so the glow dominates it. + largeFaint.Size = new Vector2(0.8f); + largeFaint + .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint) + .FadeOut(duration * 2); + + const float angle_variangle = 15; // should be less than 45 + directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4); + directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5); + + this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out).Expire(); + } + + private void setColour(Color4 objectColour) + { + const float roundness = 100; + + largeFaint.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f), + Roundness = 160, + Radius = 200, + }; + + smallFaint.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1), + Roundness = 20, + Radius = 50, + }; + + directionalGlow1.EdgeEffect = directionalGlow2.EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Glow, + Colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1), + Roundness = roundness, + Radius = 40, + }; + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index d9ab428231..7f3b1619ce 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -1,129 +1,42 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Effects; -using osu.Framework.Utils; +using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Objects.Pooling; -using osu.Game.Utils; -using osuTK; -using osuTK.Graphics; +using osu.Game.Skinning; namespace osu.Game.Rulesets.Catch.UI { public class HitExplosion : PoolableDrawableWithLifetime { - private readonly CircularContainer largeFaint; - private readonly CircularContainer smallFaint; - private readonly CircularContainer directionalGlow1; - private readonly CircularContainer directionalGlow2; + [Cached] + private Bindable bindableEntry { get; set; } = new Bindable(); public HitExplosion() { - Size = new Vector2(20); - Anchor = Anchor.TopCentre; + RelativeSizeAxes = Axes.Both; + Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; + } - // scale roughly in-line with visual appearance of notes - const float initial_height = 10; - - InternalChildren = new Drawable[] + [BackgroundDependencyLoader] + private void load() + { + InternalChild = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { - largeFaint = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Blending = BlendingParameters.Additive, - }, - smallFaint = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Blending = BlendingParameters.Additive, - }, - directionalGlow1 = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Size = new Vector2(0.01f, initial_height), - Blending = BlendingParameters.Additive, - }, - directionalGlow2 = new CircularContainer - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.Both, - Masking = true, - Size = new Vector2(0.01f, initial_height), - Blending = BlendingParameters.Additive, - } + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre }; } protected override void OnApply(HitExplosionEntry entry) { - X = entry.Position; - Scale = new Vector2(entry.Scale); - setColour(entry.ObjectColour); + base.OnApply(entry); - using (BeginAbsoluteSequence(entry.LifetimeStart)) - applyTransforms(entry.RNGSeed); - } - - private void applyTransforms(int randomSeed) - { - ClearTransforms(true); - - const double duration = 400; - - // we want our size to be very small so the glow dominates it. - largeFaint.Size = new Vector2(0.8f); - largeFaint - .ResizeTo(largeFaint.Size * new Vector2(5, 1), duration, Easing.OutQuint) - .FadeOut(duration * 2); - - const float angle_variangle = 15; // should be less than 45 - directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4); - directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5); - - this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out).Expire(); - } - - private void setColour(Color4 objectColour) - { - const float roundness = 100; - - largeFaint.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.1f, objectColour, Color4.White, 0, 1).Opacity(0.3f), - Roundness = 160, - Radius = 200, - }; - - smallFaint.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.6f, objectColour, Color4.White, 0, 1), - Roundness = 20, - Radius = 50, - }; - - directionalGlow1.EdgeEffect = directionalGlow2.EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Glow, - Colour = Interpolation.ValueAt(0.4f, objectColour, Color4.White, 0, 1), - Roundness = roundness, - Radius = 40, - }; + bindableEntry.Value = entry; } } } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs index 094d88243a..6df13e52ef 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosionContainer.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; using osu.Framework.Graphics.Pooling; using osu.Game.Rulesets.Objects.Pooling; @@ -14,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.UI public HitExplosionContainer() { + RelativeSizeAxes = Axes.Both; + AddInternal(pool = new DrawablePool(10)); } From 95a58ca3666dfe785034741caa6d4f5ac39b9170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 25 Jul 2021 17:19:51 +0200 Subject: [PATCH 145/961] Store judgement directly in hit explosion entry --- .../Skinning/Default/DefaultHitExplosion.cs | 4 +-- osu.Game.Rulesets.Catch/UI/Catcher.cs | 6 ++-- .../UI/HitExplosionEntry.cs | 30 ++++++++++++++----- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index 41ba81d34c..f4b952c559 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -87,11 +87,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default return; X = entry.Position; - Scale = new Vector2(entry.Scale); + Scale = new Vector2(entry.HitObject.Scale); setColour(entry.ObjectColour); using (BeginAbsoluteSequence(entry.LifetimeStart)) - applyTransforms(entry.RNGSeed); + applyTransforms(entry.HitObject.RandomSeed); } private void applyTransforms(int randomSeed) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 9fd4610e6e..a1aa58f163 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -216,7 +216,7 @@ namespace osu.Game.Rulesets.Catch.UI placeCaughtObject(palpableObject, positionInStack); if (hitLighting.Value) - addLighting(hitObject, positionInStack.X, drawableObject.AccentColour.Value); + addLighting(result, drawableObject.AccentColour.Value, positionInStack.X); } // droplet doesn't affect the catcher state @@ -365,8 +365,8 @@ namespace osu.Game.Rulesets.Catch.UI return position; } - private void addLighting(CatchHitObject hitObject, float x, Color4 colour) => - hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, x, hitObject.Scale, colour, hitObject.RandomSeed)); + private void addLighting(JudgementResult judgementResult, Color4 colour, float x) => + hitExplosionContainer.Add(new HitExplosionEntry(judgementResult, colour, x, Time.Current)); private CaughtObject getCaughtObject(PalpableCatchHitObject source) { diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs index b142962a8a..749a448314 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs @@ -2,24 +2,40 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics.Performance; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Judgements; using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { public class HitExplosionEntry : LifetimeEntry { - public readonly float Position; - public readonly float Scale; - public readonly Color4 ObjectColour; - public readonly int RNGSeed; + /// + /// The judgement result that triggered this explosion. + /// + public JudgementResult JudgementResult { get; } - public HitExplosionEntry(double startTime, float position, float scale, Color4 objectColour, int rngSeed) + /// + /// The hitobject which triggered this explosion. + /// + public CatchHitObject HitObject => (CatchHitObject)JudgementResult.HitObject; + + /// + /// The accent colour of the object caught. + /// + public Color4 ObjectColour { get; } + + /// + /// The position at which the object was caught. + /// + public float Position { get; } + + public HitExplosionEntry(JudgementResult judgementResult, Color4 objectColour, float position, double startTime) { LifetimeStart = startTime; Position = position; - Scale = scale; + JudgementResult = judgementResult; ObjectColour = objectColour; - RNGSeed = rngSeed; } } } From 8c8a64fe6eafc5452c2f63c3b0c464bc025389bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 25 Jul 2021 19:00:37 +0200 Subject: [PATCH 146/961] Add legacy hit lighting implementation --- .../Legacy/CatchLegacySkinTransformer.cs | 20 +++- .../Skinning/Legacy/LegacyHitExplosion.cs | 103 ++++++++++++++++++ osu.Game.Rulesets.Catch/UI/Catcher.cs | 7 +- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 1 + 4 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs index 5e744ec001..10fc4e78b2 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/CatchLegacySkinTransformer.cs @@ -70,13 +70,11 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy if (version < 2.3m) { - if (GetTexture(@"fruit-ryuuta") != null || - GetTexture(@"fruit-ryuuta-0") != null) + if (hasOldStyleCatcherSprite()) return new LegacyCatcherOld(); } - if (GetTexture(@"fruit-catcher-idle") != null || - GetTexture(@"fruit-catcher-idle-0") != null) + if (hasNewStyleCatcherSprite()) return new LegacyCatcherNew(); return null; @@ -86,12 +84,26 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy return new LegacyCatchComboCounter(Skin); return null; + + case CatchSkinComponents.HitExplosion: + if (hasOldStyleCatcherSprite() || hasNewStyleCatcherSprite()) + return new LegacyHitExplosion(); + + return null; } } return base.GetDrawableComponent(component); } + private bool hasOldStyleCatcherSprite() => + GetTexture(@"fruit-ryuuta") != null + || GetTexture(@"fruit-ryuuta-0") != null; + + private bool hasNewStyleCatcherSprite() => + GetTexture(@"fruit-catcher-idle") != null + || GetTexture(@"fruit-catcher-idle-0") != null; + public override IBindable GetConfig(TLookup lookup) { switch (lookup) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs new file mode 100644 index 0000000000..339055c91d --- /dev/null +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -0,0 +1,103 @@ +// 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.Sprites; +using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Catch.UI; +using osu.Game.Skinning; +using osuTK; + +namespace osu.Game.Rulesets.Catch.Skinning.Legacy +{ + public class LegacyHitExplosion : CompositeDrawable + { + [Resolved] + private Catcher catcher { get; set; } + + [Resolved] + private Bindable entryBindable { get; set; } + + private const float catch_margin = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2; + + private readonly Sprite explosion1; + private readonly Sprite explosion2; + + public LegacyHitExplosion() + { + Anchor = Anchor.BottomCentre; + Origin = Anchor.BottomCentre; + RelativeSizeAxes = Axes.Both; + Scale = new Vector2(0.4f); + + InternalChildren = new[] + { + explosion1 = new Sprite + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.CentreLeft, + Blending = BlendingParameters.Additive, + Rotation = -90 + }, + explosion2 = new Sprite + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.CentreLeft, + Blending = BlendingParameters.Additive, + Rotation = -90 + } + }; + } + + [BackgroundDependencyLoader] + private void load(SkinManager skins) + { + var defaultLegacySkin = skins.DefaultLegacySkin; + + explosion1.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-2"); + explosion2.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-1"); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + entryBindable.BindValueChanged(entry => apply(entry.NewValue), true); + } + + private void apply(HitExplosionEntry entry) + { + if (entry == null) + return; + + Colour = entry.ObjectColour; + + using (BeginAbsoluteSequence(entry.LifetimeStart)) + { + float halfCatchWidth = catcher.CatchWidth / 2; + float explosionOffset = Math.Clamp(entry.Position, -halfCatchWidth + catch_margin * 3, halfCatchWidth - catch_margin * 3); + + if (!(entry.HitObject is Droplet)) + { + float scale = Math.Clamp(entry.JudgementResult.ComboAtJudgement / 200f, 0.35f, 1.125f); + + explosion1.Scale = new Vector2(1, 0.9f); + explosion1.Position = new Vector2(explosionOffset, 0); + + explosion1.FadeOut(300); + explosion1.ScaleTo(new Vector2(20 * scale, 1.1f), 160, Easing.Out); + } + + explosion2.Scale = new Vector2(0.9f, 1); + explosion2.Position = new Vector2(explosionOffset, 0); + + explosion2.FadeOut(700); + explosion2.ScaleTo(new Vector2(0.9f, 1.3f), 500, Easing.Out); + } + } + } +} diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index a1aa58f163..aec8e752a7 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -23,6 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { + [Cached] public class Catcher : SkinReloadableDrawable { /// @@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Catch.UI /// /// Width of the area that can be used to attempt catches during gameplay. /// - private readonly float catchWidth; + public readonly float CatchWidth; private readonly SkinnableCatcher body; @@ -133,7 +134,7 @@ namespace osu.Game.Rulesets.Catch.UI if (difficulty != null) Scale = calculateScale(difficulty); - catchWidth = CalculateCatchWidth(Scale); + CatchWidth = CalculateCatchWidth(Scale); InternalChildren = new Drawable[] { @@ -193,7 +194,7 @@ namespace osu.Game.Rulesets.Catch.UI if (!(hitObject is PalpableCatchHitObject fruit)) return false; - float halfCatchWidth = catchWidth * 0.5f; + float halfCatchWidth = CatchWidth * 0.5f; return fruit.EffectiveX >= X - halfCatchWidth && fruit.EffectiveX <= X + halfCatchWidth; } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 7f3b1619ce..671b14640d 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -27,6 +27,7 @@ namespace osu.Game.Rulesets.Catch.UI { InternalChild = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { + CentreComponent = false, Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre }; From 4bcbe6ac90def30bda7da29052b748bc5a2b1359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 7 Aug 2021 18:19:29 +0200 Subject: [PATCH 147/961] Restructure explosion to ensure proper lifetime bounds --- .../Skinning/Default/DefaultHitExplosion.cs | 17 +++------------ .../Skinning/Legacy/LegacyHitExplosion.cs | 21 ++++++------------- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 12 ++++++----- osu.Game.Rulesets.Catch/UI/IHitExplosion.cs | 16 ++++++++++++++ 4 files changed, 32 insertions(+), 34 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/IHitExplosion.cs diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index f4b952c559..2660e0730d 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,11 +14,8 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.Skinning.Default { - public class DefaultHitExplosion : CompositeDrawable + public class DefaultHitExplosion : CompositeDrawable, IHitExplosion { - [Resolved] - private Bindable entryBindable { get; set; } - private CircularContainer largeFaint; private CircularContainer smallFaint; private CircularContainer directionalGlow1; @@ -74,14 +70,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default }; } - protected override void LoadComplete() - { - base.LoadComplete(); - - entryBindable.BindValueChanged(entry => apply(entry.NewValue), true); - } - - private void apply(HitExplosionEntry entry) + public void Animate(HitExplosionEntry entry) { if (entry == null) return; @@ -110,7 +99,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default directionalGlow1.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 4); directionalGlow2.Rotation = StatelessRNG.NextSingle(-angle_variangle, angle_variangle, randomSeed, 5); - this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out).Expire(); + this.FadeInFromZero(50).Then().FadeOut(duration, Easing.Out); } private void setColour(Color4 objectColour) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 339055c91d..6708989b89 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -3,7 +3,6 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -14,14 +13,11 @@ using osuTK; namespace osu.Game.Rulesets.Catch.Skinning.Legacy { - public class LegacyHitExplosion : CompositeDrawable + public class LegacyHitExplosion : CompositeDrawable, IHitExplosion { [Resolved] private Catcher catcher { get; set; } - [Resolved] - private Bindable entryBindable { get; set; } - private const float catch_margin = (1 - Catcher.ALLOWED_CATCH_RANGE) / 2; private readonly Sprite explosion1; @@ -62,14 +58,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy explosion2.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-1"); } - protected override void LoadComplete() - { - base.LoadComplete(); - - entryBindable.BindValueChanged(entry => apply(entry.NewValue), true); - } - - private void apply(HitExplosionEntry entry) + public void Animate(HitExplosionEntry entry) { if (entry == null) return; @@ -88,15 +77,17 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy explosion1.Scale = new Vector2(1, 0.9f); explosion1.Position = new Vector2(explosionOffset, 0); - explosion1.FadeOut(300); + explosion1.FadeOutFromOne(300); explosion1.ScaleTo(new Vector2(20 * scale, 1.1f), 160, Easing.Out); } explosion2.Scale = new Vector2(0.9f, 1); explosion2.Position = new Vector2(explosionOffset, 0); - explosion2.FadeOut(700); + explosion2.FadeOutFromOne(700); explosion2.ScaleTo(new Vector2(0.9f, 1.3f), 500, Easing.Out); + + this.Delay(700).FadeOutFromOne(); } } } diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 671b14640d..0a5341cb67 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -2,7 +2,6 @@ // 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.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Objects.Pooling; @@ -12,8 +11,7 @@ namespace osu.Game.Rulesets.Catch.UI { public class HitExplosion : PoolableDrawableWithLifetime { - [Cached] - private Bindable bindableEntry { get; set; } = new Bindable(); + private SkinnableDrawable skinnableExplosion; public HitExplosion() { @@ -25,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.UI [BackgroundDependencyLoader] private void load() { - InternalChild = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) + InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { CentreComponent = false, Anchor = Anchor.BottomCentre, @@ -37,7 +35,11 @@ namespace osu.Game.Rulesets.Catch.UI { base.OnApply(entry); - bindableEntry.Value = entry; + ApplyTransformsAt(double.MinValue, true); + ClearTransforms(true); + + (skinnableExplosion.Drawable as IHitExplosion)?.Animate(entry); + LifetimeEnd = skinnableExplosion.Drawable.LatestTransformEndTime; } } } diff --git a/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs b/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs new file mode 100644 index 0000000000..4a9d7e8ac0 --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Catch.UI +{ + /// + /// Common interface for all hit explosion skinnables. + /// + public interface IHitExplosion + { + /// + /// Begins animating this . + /// + void Animate(HitExplosionEntry entry); + } +} From 2fb19210af31d7aba85348c4b8bc3f023f0e61da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 11 Aug 2021 22:36:27 +0200 Subject: [PATCH 148/961] Fix legacy explosion sprites incorrectly showing after skin change --- osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 6708989b89..78b0e1e327 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -36,6 +36,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { Anchor = Anchor.BottomCentre, Origin = Anchor.CentreLeft, + Alpha = 0, Blending = BlendingParameters.Additive, Rotation = -90 }, @@ -43,6 +44,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { Anchor = Anchor.BottomCentre, Origin = Anchor.CentreLeft, + Alpha = 0, Blending = BlendingParameters.Additive, Rotation = -90 } From 427a88940c56988484a17c0e0020613243be9083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 11 Aug 2021 23:18:42 +0200 Subject: [PATCH 149/961] Remove duplicated `ClearTransforms()` call --- osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index 2660e0730d..680fbc7b15 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -85,8 +85,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default private void applyTransforms(int randomSeed) { - ClearTransforms(true); - const double duration = 400; // we want our size to be very small so the glow dominates it. From 98ce69d1d32b65abd9983dbd1124cad8f6bc938b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 11 Aug 2021 23:32:58 +0200 Subject: [PATCH 150/961] Fix explosion reading out time values from wrong clock --- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 0a5341cb67..35af39348d 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -34,7 +34,18 @@ namespace osu.Game.Rulesets.Catch.UI protected override void OnApply(HitExplosionEntry entry) { base.OnApply(entry); + if (IsLoaded) + apply(entry); + } + protected override void LoadComplete() + { + base.LoadComplete(); + apply(Entry); + } + + private void apply(HitExplosionEntry entry) + { ApplyTransformsAt(double.MinValue, true); ClearTransforms(true); From 58d76e903618e640fe97d9b341959cca33804940 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 09:13:10 +0900 Subject: [PATCH 151/961] Use FinishTransforms() --- .../Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs index dfe7ff8cac..052ad35dd7 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs @@ -21,7 +21,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [Resolved] private OsuColour colours { get; set; } - private bool firstDisplay = true; private PillContainer pill; private SpriteText statusText; @@ -51,6 +50,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components EndDate.BindValueChanged(_ => updateDisplay()); Status.BindValueChanged(_ => updateDisplay(), true); + + FinishTransforms(true); } private void updateDisplay() @@ -58,10 +59,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RoomStatus status = getDisplayStatus(); pill.Background.Alpha = 1; - pill.Background.FadeColour(status.GetAppropriateColour(colours), firstDisplay ? 0 : 100); + pill.Background.FadeColour(status.GetAppropriateColour(colours), 100); statusText.Text = status.Message; - - firstDisplay = false; } private RoomStatus getDisplayStatus() From bbb28d1b2984c2478414e068830aa54c9b4beb03 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 09:14:46 +0900 Subject: [PATCH 152/961] Don't use null-propagation for status --- osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs index 052ad35dd7..1d43f2dc65 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomStatusPill.cs @@ -68,7 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components if (EndDate.Value < DateTimeOffset.Now) return new RoomStatusEnded(); - return Status.Value ?? new RoomStatusOpen(); + return Status.Value; } } } From fbaa480b3e21808f15e6e3cbef7262e440f2ca66 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 10:08:54 +0900 Subject: [PATCH 153/961] Fix out-of-order hits in editor causing exceptions --- .../Edit/DrawableOsuEditorRuleset.cs | 5 +++++ osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.cs | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.cs diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index 0e61c02e2d..d4f1602a46 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -41,6 +41,11 @@ namespace osu.Game.Rulesets.Osu.Edit protected override GameplayCursorContainer CreateCursor() => null; + public OsuEditorPlayfield() + { + HitPolicy = new AnyOrderHitPolicy(); + } + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { diff --git a/osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.cs b/osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.cs new file mode 100644 index 0000000000..b4de91562b --- /dev/null +++ b/osu.Game.Rulesets.Osu/UI/AnyOrderHitPolicy.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.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Osu.UI +{ + /// + /// An which allows hitobjects to be hit in any order. + /// + public class AnyOrderHitPolicy : IHitPolicy + { + public IHitObjectContainer HitObjectContainer { get; set; } + + public bool IsHittable(DrawableHitObject hitObject, double time) => true; + + public void HandleHit(DrawableHitObject hitObject) + { + } + } +} From 5d0b92e28cdff72e8185827d34f7cff5ddb3d191 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 10:38:20 +0900 Subject: [PATCH 154/961] Fix multi spectator test not showing teams --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 3118a23fd5..65b1d6d53a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -97,11 +97,11 @@ namespace osu.Game.Tests.Visual.Multiplayer TeamID = 1, }; - SpectatorClient.StartPlay(PLAYER_1_ID, importedBeatmapId); - SpectatorClient.StartPlay(PLAYER_2_ID, importedBeatmapId); + SpectatorClient.StartPlay(player1.UserID, importedBeatmapId); + SpectatorClient.StartPlay(player2.UserID, importedBeatmapId); - playingUsers.Add(new MultiplayerRoomUser(PLAYER_1_ID)); - playingUsers.Add(new MultiplayerRoomUser(PLAYER_2_ID)); + playingUsers.Add(player1); + playingUsers.Add(player2); }); loadSpectateScreen(); From 543482111b470d63cf74c4ed6dab294282fa7af8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 10:40:14 +0900 Subject: [PATCH 155/961] Remove outdated todo --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index 2846fbec29..d10917259d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -55,7 +55,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate public MultiSpectatorScreen(MultiplayerRoomUser[] users) : base(users.Select(u => u.UserID).ToArray()) { - // todo: this is a bit ugly, but not sure on a better way to handle. this.users = users; instances = new PlayerArea[Users.Count]; From 531fba8f39949265ef61cd17a3c66d881695c9e4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 11:05:31 +0900 Subject: [PATCH 156/961] Fix potential test case failure --- .../TestSceneMultiplayerGameplayLeaderboard.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs index 0997de478b..3317ddc767 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs @@ -12,6 +12,7 @@ using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu.Scoring; @@ -51,12 +52,13 @@ namespace osu.Game.Tests.Visual.Multiplayer OsuScoreProcessor scoreProcessor; Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); - var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + var multiplayerUsers = new List(); foreach (var user in users) { SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0); - OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true); + multiplayerUsers.Add(OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true)); } Children = new Drawable[] @@ -64,9 +66,9 @@ namespace osu.Game.Tests.Visual.Multiplayer scoreProcessor = new OsuScoreProcessor(), }; - scoreProcessor.ApplyBeatmap(playable); + scoreProcessor.ApplyBeatmap(playableBeatmap); - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray()) + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, multiplayerUsers.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, From 9393c6351d41a7affb43988a1d6932476d31c99a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 11:08:52 +0900 Subject: [PATCH 157/961] Fix another potential test case failure --- .../TestSceneMultiplayerGameplayLeaderboardTeams.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs index 274c9ea4b2..dfaf2f1dc3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboardTeams.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Online.API; +using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Osu.Scoring; @@ -55,7 +56,8 @@ namespace osu.Game.Tests.Visual.Multiplayer OsuScoreProcessor scoreProcessor; Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value); - var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value); + var multiplayerUsers = new List(); foreach (var user in users) { @@ -66,6 +68,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { TeamID = RNG.Next(0, 2) }; + + multiplayerUsers.Add(roomUser); } Children = new Drawable[] @@ -73,9 +77,9 @@ namespace osu.Game.Tests.Visual.Multiplayer scoreProcessor = new OsuScoreProcessor(), }; - scoreProcessor.ApplyBeatmap(playable); + scoreProcessor.ApplyBeatmap(playableBeatmap); - LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, Client.Room?.Users.ToArray()) + LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(scoreProcessor, multiplayerUsers.ToArray()) { Anchor = Anchor.Centre, Origin = Anchor.Centre, From 18ecd8758ba0646e5c54621eb77d23d152eea397 Mon Sep 17 00:00:00 2001 From: PercyDan <50285552+PercyDan54@users.noreply.github.com> Date: Thu, 12 Aug 2021 10:12:35 +0800 Subject: [PATCH 158/961] Make Perfect auto restart toggleable --- osu.Game/Rulesets/Mods/ModFailCondition.cs | 5 +++++ osu.Game/Rulesets/Mods/ModPerfect.cs | 5 +++++ osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 5 ----- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs index c0d7bae2b2..c6855a3d38 100644 --- a/osu.Game/Rulesets/Mods/ModFailCondition.cs +++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Bindables; +using osu.Game.Configuration; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -11,6 +13,9 @@ namespace osu.Game.Rulesets.Mods { public override Type[] IncompatibleMods => new[] { typeof(ModNoFail), typeof(ModRelax), typeof(ModAutoplay) }; + [SettingSource("Restart on fail", "Automatically restarts when failed.")] + public BindableBool Restart { get; } = new BindableBool(); + public virtual bool PerformFail() => true; public virtual bool RestartOnFail => true; diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs index 187a4d8e23..9016a24f8d 100644 --- a/osu.Game/Rulesets/Mods/ModPerfect.cs +++ b/osu.Game/Rulesets/Mods/ModPerfect.cs @@ -21,6 +21,11 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModSuddenDeath)).ToArray(); + protected ModPerfect() + { + Restart.Value = Restart.Default = true; + } + protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type.AffectsAccuracy() && result.Type != result.Judgement.MaxResult; diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 7df561b199..68ed112078 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -3,9 +3,7 @@ using System; using System.Linq; -using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; -using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; @@ -23,9 +21,6 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModPerfect)).ToArray(); - [SettingSource("Restart on fail", "Automatically restarts when failed.")] - public BindableBool Restart { get; } = new BindableBool(); - public override bool PerformFail() => true; public override bool RestartOnFail => Restart.Value; From d80a2dcca72da28a9fac4a6ec3c5abff2d5ddf30 Mon Sep 17 00:00:00 2001 From: PercyDan <50285552+PercyDan54@users.noreply.github.com> Date: Thu, 12 Aug 2021 10:14:01 +0800 Subject: [PATCH 159/961] Missed one --- osu.Game/Rulesets/Mods/ModFailCondition.cs | 2 +- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModFailCondition.cs b/osu.Game/Rulesets/Mods/ModFailCondition.cs index c6855a3d38..4425ece513 100644 --- a/osu.Game/Rulesets/Mods/ModFailCondition.cs +++ b/osu.Game/Rulesets/Mods/ModFailCondition.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Mods public virtual bool PerformFail() => true; - public virtual bool RestartOnFail => true; + public virtual bool RestartOnFail => Restart.Value; public void ApplyToHealthProcessor(HealthProcessor healthProcessor) { diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 68ed112078..031eb716c3 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -23,8 +23,6 @@ namespace osu.Game.Rulesets.Mods public override bool PerformFail() => true; - public override bool RestartOnFail => Restart.Value; - protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type.AffectsCombo() && !result.IsHit; From 6ecc728c0121e4821cf83346e2cf8a5401a6210e Mon Sep 17 00:00:00 2001 From: PercyDan <50285552+PercyDan54@users.noreply.github.com> Date: Thu, 12 Aug 2021 10:27:36 +0800 Subject: [PATCH 160/961] Remove override --- osu.Game/Rulesets/Mods/ModSuddenDeath.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index 031eb716c3..1abd353d20 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Mods public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModPerfect)).ToArray(); - public override bool PerformFail() => true; - protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type.AffectsCombo() && !result.IsHit; From 97041de09f5230e2fe1d5d9004e74b920be8b42b Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Wed, 11 Aug 2021 11:23:12 +0800 Subject: [PATCH 161/961] Preparation for localisation. --- osu.Game/Overlays/Settings/SettingsSection.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index 4143605c28..f993a46dc6 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK.Graphics; @@ -19,10 +20,10 @@ namespace osu.Game.Overlays.Settings protected override Container Content => FlowContent; public abstract Drawable CreateIcon(); - public abstract string Header { get; } + public abstract LocalisableString Header { get; } public IEnumerable FilterableChildren => Children.OfType(); - public virtual IEnumerable FilterTerms => new[] { Header }; + public virtual IEnumerable FilterTerms => new[] { Header.ToString() }; private const int header_size = 26; private const int margin = 20; From 9a5d4ffd43e1fc2fed39cf03992ff7e503cd5473 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Wed, 11 Aug 2021 15:25:08 +0800 Subject: [PATCH 162/961] Add GeneralSettingsStrings --- .../Localisation/GeneralSettingsStrings.cs | 59 +++++++++++++++++++ .../Sections/General/LanguageSettings.cs | 6 +- .../Sections/General/UpdateSettings.cs | 11 ++-- .../Settings/Sections/GeneralSection.cs | 4 +- 4 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Localisation/GeneralSettingsStrings.cs diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs new file mode 100644 index 0000000000..19fb8de972 --- /dev/null +++ b/osu.Game/Localisation/GeneralSettingsStrings.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.Localisation; + +namespace osu.Game.Localisation +{ + public static class GeneralSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.GeneralSettings"; + + /// + /// "General" + /// + public static LocalisableString GeneralSectionHeader => new TranslatableString(getKey(@"general_section_header"), @"General"); + + /// + /// "Language" + /// + public static LocalisableString LanguageHeader => new TranslatableString(getKey(@"language_header"), @"Language"); + + /// + /// "Language" + /// + public static LocalisableString LanguageDropdown => new TranslatableString(getKey(@"language_dropdown"), @"Language"); + + /// + /// "Prefer metadata in original language" + /// + public static LocalisableString PreferOriginal => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language"); + + /// + /// "Updates" + /// + public static LocalisableString UpdateHeader => new TranslatableString(getKey(@"update_header"), @"Updates"); + + /// + /// "Release stream" + /// + public static LocalisableString ReleaseStream => new TranslatableString(getKey(@"release_stream"), @"Release stream"); + + /// + /// "Check for updates" + /// + public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates"); + + /// + /// "Open osu! folder" + /// + public static LocalisableString OpenOsuFolder => new TranslatableString(getKey(@"open_osu_folder"), @"Open osu! folder"); + + /// + /// "Change folder location..." + /// + public static LocalisableString ChangeFolderLocation => new TranslatableString(getKey(@"change_folder_location"), @"Change folder location..."); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index c6c752e2fd..ac95a713bf 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -16,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.General private SettingsDropdown languageSelection; private Bindable frameworkLocale; - protected override LocalisableString Header => "Language"; + protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader; [BackgroundDependencyLoader] private void load(FrameworkConfigManager frameworkConfig) @@ -27,11 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.General { languageSelection = new SettingsEnumDropdown { - LabelText = "Language", + LabelText = GeneralSettingsStrings.LanguageDropdown, }, new SettingsCheckbox { - LabelText = "Prefer metadata in original language", + LabelText = GeneralSettingsStrings.PreferOriginal, Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode) }, }; diff --git a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs index dd20e1d7ef..aa37748653 100644 --- a/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/UpdateSettings.cs @@ -9,6 +9,7 @@ using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Settings.Sections.Maintenance; using osu.Game.Updater; @@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.General [Resolved(CanBeNull = true)] private UpdateManager updateManager { get; set; } - protected override LocalisableString Header => "Updates"; + protected override LocalisableString Header => GeneralSettingsStrings.UpdateHeader; private SettingsButton checkForUpdatesButton; @@ -32,7 +33,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { Add(new SettingsEnumDropdown { - LabelText = "Release stream", + LabelText = GeneralSettingsStrings.ReleaseStream, Current = config.GetBindable(OsuSetting.ReleaseStream), }); @@ -40,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { Add(checkForUpdatesButton = new SettingsButton { - Text = "Check for updates", + Text = GeneralSettingsStrings.CheckUpdate, Action = () => { checkForUpdatesButton.Enabled.Value = false; @@ -65,13 +66,13 @@ namespace osu.Game.Overlays.Settings.Sections.General { Add(new SettingsButton { - Text = "Open osu! folder", + Text = GeneralSettingsStrings.OpenOsuFolder, Action = storage.OpenInNativeExplorer, }); Add(new SettingsButton { - Text = "Change folder location...", + Text = GeneralSettingsStrings.ChangeFolderLocation, Action = () => game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen())) }); } diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index fefc3fe6a7..87e9f34833 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -3,13 +3,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.General; namespace osu.Game.Overlays.Settings.Sections { public class GeneralSection : SettingsSection { - public override string Header => "General"; + public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From 078953980e65c4639899833556b6cd3969e6fd1c Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Wed, 11 Aug 2021 16:48:37 +0800 Subject: [PATCH 163/961] Add GraphicsSettingsStrings --- osu.Game/Localisation/CommonStrings.cs | 7 +- .../Localisation/GraphicsSettingsStrings.cs | 119 ++++++++++++++++++ .../Sections/Graphics/DetailSettings.cs | 11 +- .../Sections/Graphics/LayoutSettings.cs | 25 ++-- .../Sections/Graphics/RendererSettings.cs | 13 +- .../Settings/Sections/GraphicsSection.cs | 4 +- 6 files changed, 152 insertions(+), 27 deletions(-) create mode 100644 osu.Game/Localisation/GraphicsSettingsStrings.cs diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index bf488d2590..5e4ce235b4 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -19,6 +19,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Enabled => new TranslatableString(getKey(@"enabled"), @"Enabled"); + /// + /// "Default" + /// + public static LocalisableString Default => new TranslatableString(getKey(@"default"), @"Default"); + /// /// "Width" /// @@ -31,4 +36,4 @@ namespace osu.Game.Localisation private static string getKey(string key) => $@"{prefix}:{key}"; } -} \ No newline at end of file +} diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs new file mode 100644 index 0000000000..841635649e --- /dev/null +++ b/osu.Game/Localisation/GraphicsSettingsStrings.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 osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class GraphicsSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.GraphicsSettings"; + + /// + /// "Graphics" + /// + public static LocalisableString GraphicsSectionHeader => new TranslatableString(getKey(@"graphics_section_header"), @"Graphics"); + + /// + /// "Renderer" + /// + public static LocalisableString RendererHeader => new TranslatableString(getKey(@"renderer_header"), @"Renderer"); + + /// + /// "Frame limiter" + /// + public static LocalisableString FrameLimiter => new TranslatableString(getKey(@"frame_limiter"), @"Frame limiter"); + + /// + /// "Threading mode" + /// + public static LocalisableString ThreadingMode => new TranslatableString(getKey(@"threading_mode"), @"Threading mode"); + + /// + /// "Show FPS" + /// + public static LocalisableString ShowFPS => new TranslatableString(getKey(@"show_fps"), @"Show FPS"); + + /// + /// "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. "2x refresh rate" is recommended." + /// + public static LocalisableString UnlimitedFramesNote => new TranslatableString(getKey(@"unlimited_frames_note"), @"Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. ""2x refresh rate"" is recommended."); + + /// + /// "Layout" + /// + public static LocalisableString LayoutHeader => new TranslatableString(getKey(@"layout_header"), @"Layout"); + + /// + /// "Screen mode" + /// + public static LocalisableString ScreenMode => new TranslatableString(getKey(@"screen_mode"), @"Screen mode"); + + /// + /// "Resolution" + /// + public static LocalisableString Resolution => new TranslatableString(getKey(@"resolution"), @"Resolution"); + + /// + /// "UI Scaling" + /// + public static LocalisableString UIScaling => new TranslatableString(getKey(@"ui_scaling"), @"UI Scaling"); + + /// + /// "Screen Scaling" + /// + public static LocalisableString ScreenScaling => new TranslatableString(getKey(@"screen_scaling"), @"Screen Scaling"); + + /// + /// "Horizontal position" + /// + public static LocalisableString HorizontalPosition => new TranslatableString(getKey(@"horizontal_position"), @"Horizontal position"); + + /// + /// "Vertical position" + /// + public static LocalisableString VerticalPosition => new TranslatableString(getKey(@"vertical_position"), @"Vertical position"); + + /// + /// "Horizontal scale" + /// + public static LocalisableString HorizontalScale => new TranslatableString(getKey(@"horizontal_scale"), @"Horizontal scale"); + + /// + /// "Vertical scale" + /// + public static LocalisableString VerticalScale => new TranslatableString(getKey(@"vertical_scale"), @"Vertical scale"); + + /// + /// "Running without fullscreen mode will increase your input latency!" + /// + public static LocalisableString NotFullscreenNote => new TranslatableString(getKey(@"not_fullscreen_note"), @"Running without fullscreen mode will increase your input latency!"); + + /// + /// "Detail Settings" + /// + public static LocalisableString DetailSettingsHeader => new TranslatableString(getKey(@"detail_settings_header"), @"Detail Settings"); + + /// + /// "Storyboard / Video" + /// + public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / Video"); + + /// + /// "Hit Lighting" + /// + public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit Lighting"); + + /// + /// "Screenshot format" + /// + public static LocalisableString ScreenshotFormat => new TranslatableString(getKey(@"screenshot_format"), @"Screenshot format"); + + /// + /// "Show menu cursor in screenshots" + /// + public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@""), @"Show menu cursor in screenshots"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs index f889cfca0f..20b1d8d801 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/DetailSettings.cs @@ -5,12 +5,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics { public class DetailSettings : SettingsSubsection { - protected override LocalisableString Header => "Detail Settings"; + protected override LocalisableString Header => GraphicsSettingsStrings.DetailSettingsHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -19,22 +20,22 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { new SettingsCheckbox { - LabelText = "Storyboard / Video", + LabelText = GraphicsSettingsStrings.StoryboardVideo, Current = config.GetBindable(OsuSetting.ShowStoryboard) }, new SettingsCheckbox { - LabelText = "Hit Lighting", + LabelText = GraphicsSettingsStrings.HitLighting, Current = config.GetBindable(OsuSetting.HitLighting) }, new SettingsEnumDropdown { - LabelText = "Screenshot format", + LabelText = GraphicsSettingsStrings.ScreenshotFormat, Current = config.GetBindable(OsuSetting.ScreenshotFormat) }, new SettingsCheckbox { - LabelText = "Show menu cursor in screenshots", + LabelText = GraphicsSettingsStrings.ShowCursorInScreenshots, Current = config.GetBindable(OsuSetting.ScreenshotCaptureMenuCursor) } }; diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 91208cb78a..50bd8184ee 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -16,13 +16,14 @@ using osu.Framework.Platform; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osuTK.Graphics; namespace osu.Game.Overlays.Settings.Sections.Graphics { public class LayoutSettings : SettingsSubsection { - protected override LocalisableString Header => "Layout"; + protected override LocalisableString Header => GraphicsSettingsStrings.LayoutHeader; private FillFlowContainer> scalingSettings; @@ -67,20 +68,20 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { windowModeDropdown = new SettingsDropdown { - LabelText = "Screen mode", + LabelText = GraphicsSettingsStrings.ScreenMode, ItemSource = windowModes, Current = config.GetBindable(FrameworkSetting.WindowMode), }, resolutionDropdown = new ResolutionSettingsDropdown { - LabelText = "Resolution", + LabelText = GraphicsSettingsStrings.Resolution, ShowsDefaultIndicator = false, ItemSource = resolutions, Current = sizeFullscreen }, new SettingsSlider { - LabelText = "UI Scaling", + LabelText = GraphicsSettingsStrings.UIScaling, TransferValueOnCommit = true, Current = osuConfig.GetBindable(OsuSetting.UIScale), KeyboardStep = 0.01f, @@ -88,7 +89,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics }, new SettingsEnumDropdown { - LabelText = "Screen Scaling", + LabelText = GraphicsSettingsStrings.ScreenScaling, Current = osuConfig.GetBindable(OsuSetting.Scaling), Keywords = new[] { "scale", "letterbox" }, }, @@ -104,28 +105,28 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { new SettingsSlider { - LabelText = "Horizontal position", + LabelText = GraphicsSettingsStrings.HorizontalPosition, Current = scalingPositionX, KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Vertical position", + LabelText = GraphicsSettingsStrings.VerticalPosition, Current = scalingPositionY, KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Horizontal scale", + LabelText = GraphicsSettingsStrings.HorizontalScale, Current = scalingSizeX, KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Vertical scale", + LabelText = GraphicsSettingsStrings.VerticalScale, Current = scalingSizeY, KeyboardStep = 0.01f, DisplayAsPercentage = true @@ -145,9 +146,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { updateResolutionDropdown(); - const string not_fullscreen_note = "Running without fullscreen mode will increase your input latency!"; - - windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? not_fullscreen_note : string.Empty; + windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : string.Empty; }, true); windowModes.BindCollectionChanged((sender, args) => @@ -245,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics protected override LocalisableString GenerateItemText(Size item) { if (item == new Size(9999, 9999)) - return "Default"; + return CommonStrings.Default; return $"{item.Width}x{item.Height}"; } diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index 2210c7911e..9747f6b373 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -7,12 +7,13 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Graphics { public class RendererSettings : SettingsSubsection { - protected override LocalisableString Header => "Renderer"; + protected override LocalisableString Header => GraphicsSettingsStrings.RendererHeader; private SettingsEnumDropdown frameLimiterDropdown; @@ -25,17 +26,17 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics // TODO: this needs to be a custom dropdown at some point frameLimiterDropdown = new SettingsEnumDropdown { - LabelText = "Frame limiter", + LabelText = GraphicsSettingsStrings.FrameLimiter, Current = config.GetBindable(FrameworkSetting.FrameSync) }, new SettingsEnumDropdown { - LabelText = "Threading mode", + LabelText = GraphicsSettingsStrings.ThreadingMode, Current = config.GetBindable(FrameworkSetting.ExecutionMode) }, new SettingsCheckbox { - LabelText = "Show FPS", + LabelText = GraphicsSettingsStrings.ShowFPS, Current = osuConfig.GetBindable(OsuSetting.ShowFpsDisplay) }, }; @@ -47,9 +48,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics frameLimiterDropdown.Current.BindValueChanged(limit => { - const string unlimited_frames_note = "Using unlimited frame limiter can lead to stutters, bad performance and overheating. It will not improve perceived latency. \"2x refresh rate\" is recommended."; - - frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? unlimited_frames_note : string.Empty; + frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : string.Empty; }, true); } } diff --git a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs index 4ade48031f..fd0718f9f2 100644 --- a/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GraphicsSection.cs @@ -3,13 +3,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Graphics; namespace osu.Game.Overlays.Settings.Sections { public class GraphicsSection : SettingsSection { - public override string Header => "Graphics"; + public override LocalisableString Header => GraphicsSettingsStrings.GraphicsSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From b2986e99d30a8e638e53047dd3b594343a18e073 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Wed, 11 Aug 2021 17:10:08 +0800 Subject: [PATCH 164/961] Add AudioSettingsStrings --- osu.Game/Localisation/AudioSettingsStrings.cs | 64 +++++++++++++++++++ .../Sections/Audio/AudioDevicesSettings.cs | 5 +- .../Settings/Sections/Audio/OffsetSettings.cs | 7 +- .../Settings/Sections/Audio/VolumeSettings.cs | 11 ++-- .../Settings/Sections/AudioSection.cs | 4 +- 5 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Localisation/AudioSettingsStrings.cs diff --git a/osu.Game/Localisation/AudioSettingsStrings.cs b/osu.Game/Localisation/AudioSettingsStrings.cs new file mode 100644 index 0000000000..aa6eabd7d1 --- /dev/null +++ b/osu.Game/Localisation/AudioSettingsStrings.cs @@ -0,0 +1,64 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class AudioSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.AudioSettings"; + + /// + /// "Audio" + /// + public static LocalisableString AudioSectionHeader => new TranslatableString(getKey(@"audio_section_header"), @"Audio"); + + /// + /// "Devices" + /// + public static LocalisableString AudioDevicesHeader => new TranslatableString(getKey(@"audio_devices_header"), @"Devices"); + + /// + /// "Volume" + /// + public static LocalisableString VolumeHeader => new TranslatableString(getKey(@"volume_header"), @"Volume"); + + /// + /// "Master" + /// + public static LocalisableString MasterVolume => new TranslatableString(getKey(@"master_volume"), @"Master"); + + /// + /// "Master (window inactive)" + /// + public static LocalisableString MasterVolumeInactive => new TranslatableString(getKey(@"master_volume_inactive"), @"Master (window inactive)"); + + /// + /// "Effect" + /// + public static LocalisableString EffectVolume => new TranslatableString(getKey(@"effect_volume"), @"Effect"); + + /// + /// "Music" + /// + public static LocalisableString MusicVolume => new TranslatableString(getKey(@"music_volume"), @"Music"); + + /// + /// "Offset Adjustment" + /// + public static LocalisableString OffsetHeader => new TranslatableString(getKey(@"offset_header"), @"Offset Adjustment"); + + /// + /// "Audio offset" + /// + public static LocalisableString AudioOffset => new TranslatableString(getKey(@"audio_offset"), @"Audio offset"); + + /// + /// "Offset wizard" + /// + public static LocalisableString OffsetWizard => new TranslatableString(getKey(@"offset_wizard"), @"Offset wizard"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index d64f176468..501f1b86b8 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -8,12 +8,13 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { public class AudioDevicesSettings : SettingsSubsection { - protected override LocalisableString Header => "Devices"; + protected override LocalisableString Header => AudioSettingsStrings.AudioDevicesHeader; [Resolved] private AudioManager audio { get; set; } @@ -78,7 +79,7 @@ namespace osu.Game.Overlays.Settings.Sections.Audio private class AudioDeviceDropdownControl : DropdownControl { protected override LocalisableString GenerateItemText(string item) - => string.IsNullOrEmpty(item) ? "Default" : base.GenerateItemText(item); + => string.IsNullOrEmpty(item) ? CommonStrings.Default : base.GenerateItemText(item); } } } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index 7f2e377c83..85973c81c9 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs @@ -6,12 +6,13 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { public class OffsetSettings : SettingsSubsection { - protected override LocalisableString Header => "Offset Adjustment"; + protected override LocalisableString Header => AudioSettingsStrings.OffsetHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -20,13 +21,13 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { new SettingsSlider { - LabelText = "Audio offset", + LabelText = AudioSettingsStrings.AudioOffset, Current = config.GetBindable(OsuSetting.AudioOffset), KeyboardStep = 1f }, new SettingsButton { - Text = "Offset wizard" + Text = AudioSettingsStrings.OffsetWizard } }; } diff --git a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs index 8f88b03471..00c1cb8f43 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/VolumeSettings.cs @@ -6,12 +6,13 @@ using osu.Framework.Audio; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Audio { public class VolumeSettings : SettingsSubsection { - protected override LocalisableString Header => "Volume"; + protected override LocalisableString Header => AudioSettingsStrings.VolumeHeader; [BackgroundDependencyLoader] private void load(AudioManager audio, OsuConfigManager config) @@ -20,28 +21,28 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { new SettingsSlider { - LabelText = "Master", + LabelText = AudioSettingsStrings.MasterVolume, Current = audio.Volume, KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Master (window inactive)", + LabelText = AudioSettingsStrings.MasterVolumeInactive, Current = config.GetBindable(OsuSetting.VolumeInactive), KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Effect", + LabelText = AudioSettingsStrings.EffectVolume, Current = audio.VolumeSample, KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Music", + LabelText = AudioSettingsStrings.MusicVolume, Current = audio.VolumeTrack, KeyboardStep = 0.01f, DisplayAsPercentage = true diff --git a/osu.Game/Overlays/Settings/Sections/AudioSection.cs b/osu.Game/Overlays/Settings/Sections/AudioSection.cs index 7072d8e63d..694da0529a 100644 --- a/osu.Game/Overlays/Settings/Sections/AudioSection.cs +++ b/osu.Game/Overlays/Settings/Sections/AudioSection.cs @@ -3,15 +3,17 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Localisation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Audio; namespace osu.Game.Overlays.Settings.Sections { public class AudioSection : SettingsSection { - public override string Header => "Audio"; + public override LocalisableString Header => AudioSettingsStrings.AudioSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From 2cc89f50cce503ed8ecd3a86206b8cd6a50660ea Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 09:14:49 +0800 Subject: [PATCH 165/961] Add missing key --- osu.Game/Localisation/GraphicsSettingsStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index 841635649e..989eaf19b9 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -112,7 +112,7 @@ namespace osu.Game.Localisation /// /// "Show menu cursor in screenshots" /// - public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@""), @"Show menu cursor in screenshots"); + public static LocalisableString ShowCursorInScreenshots => new TranslatableString(getKey(@"show_cursor_in_screenshots"), @"Show menu cursor in screenshots"); private static string getKey(string key) => $"{prefix}:{key}"; } From 03013d0d307480f3589714dd4b6043555fb4943d Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 09:53:31 +0800 Subject: [PATCH 166/961] Add InputSettingsStrings Existed strings files keep no change --- osu.Game/Localisation/CommonStrings.cs | 5 ++ osu.Game/Localisation/InputSettingsStrings.cs | 59 +++++++++++++++++++ .../Input/GlobalKeyBindingsSection.cs | 11 ++-- .../Sections/Input/KeyBindingPanel.cs | 3 +- .../Settings/Sections/Input/KeyBindingRow.cs | 5 +- .../Sections/Input/KeyBindingsSubsection.cs | 3 +- .../Sections/Input/RulesetBindingsSection.cs | 3 +- .../Settings/Sections/InputSection.cs | 5 +- 8 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Localisation/InputSettingsStrings.cs diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 5e4ce235b4..432c1c6255 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -14,6 +14,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel"); + /// + /// "Clear" + /// + public static LocalisableString Clear => new TranslatableString(getKey(@"clear"), @"Clear"); + /// /// "Enabled" /// diff --git a/osu.Game/Localisation/InputSettingsStrings.cs b/osu.Game/Localisation/InputSettingsStrings.cs new file mode 100644 index 0000000000..e46b4cecf3 --- /dev/null +++ b/osu.Game/Localisation/InputSettingsStrings.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.Localisation; + +namespace osu.Game.Localisation +{ + public static class InputSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.InputSettings"; + + /// + /// "Input" + /// + public static LocalisableString InputSectionHeader => new TranslatableString(getKey(@"input_section_header"), @"Input"); + + /// + /// "Global" + /// + public static LocalisableString GlobalKeyBindingHeader => new TranslatableString(getKey(@"global_key_binding_header"), @"Global"); + + /// + /// "Song Select" + /// + public static LocalisableString SongSelectSection => new TranslatableString(getKey(@"song_select_section"), @"Song Select"); + + /// + /// "In Game" + /// + public static LocalisableString InGameSection => new TranslatableString(getKey(@"in_game_section"), @"In Game"); + + /// + /// "Audio" + /// + public static LocalisableString AudioSection => new TranslatableString(getKey(@"audio_section"), @"Audio"); + + /// + /// "Editor" + /// + public static LocalisableString EditorSection => new TranslatableString(getKey(@"editor_section"), @"Editor"); + + /// + /// "Reset all bindings in section" + /// + public static LocalisableString ResetSectionButton => new TranslatableString(getKey(@"reset_section_button"), @"Reset all bindings in section"); + + /// + /// "key configuration" + /// + public static LocalisableString KeyBindingPanelHeader => new TranslatableString(getKey(@"key_binding_panel_header"), @"key configuration"); + + /// + /// "Customise your keys!" + /// + public static LocalisableString KeyBindingPanelDescription => new TranslatableString(getKey(@"key_binding_panel_description"), @"Customise your keys!"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs index 9898a50320..3350ff4eaa 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/GlobalKeyBindingsSection.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Game.Input.Bindings; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Input { @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Icon = FontAwesome.Solid.Globe }; - public override string Header => "Global"; + public override LocalisableString Header => InputSettingsStrings.GlobalKeyBindingHeader; public GlobalKeyBindingsSection(GlobalActionContainer manager) { @@ -39,7 +40,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input private class SongSelectKeyBindingSubsection : KeyBindingsSubsection { - protected override LocalisableString Header => "Song Select"; + protected override LocalisableString Header => InputSettingsStrings.SongSelectSection; public SongSelectKeyBindingSubsection(GlobalActionContainer manager) : base(null) @@ -50,7 +51,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input private class InGameKeyBindingsSubsection : KeyBindingsSubsection { - protected override LocalisableString Header => "In Game"; + protected override LocalisableString Header => InputSettingsStrings.InGameSection; public InGameKeyBindingsSubsection(GlobalActionContainer manager) : base(null) @@ -61,7 +62,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input private class AudioControlKeyBindingsSubsection : KeyBindingsSubsection { - protected override LocalisableString Header => "Audio"; + protected override LocalisableString Header => InputSettingsStrings.AudioSection; public AudioControlKeyBindingsSubsection(GlobalActionContainer manager) : base(null) @@ -72,7 +73,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input private class EditorKeyBindingsSubsection : KeyBindingsSubsection { - protected override LocalisableString Header => "Editor"; + protected override LocalisableString Header => InputSettingsStrings.EditorSection; public EditorKeyBindingsSubsection(GlobalActionContainer manager) : base(null) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs index 7cdc739b7c..67f1bb8d3e 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingPanel.cs @@ -4,13 +4,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Input.Bindings; +using osu.Game.Localisation; using osu.Game.Rulesets; namespace osu.Game.Overlays.Settings.Sections.Input { public class KeyBindingPanel : SettingsSubPanel { - protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!"); + protected override Drawable CreateHeader() => new SettingsHeader(InputSettingsStrings.KeyBindingPanelHeader, InputSettingsStrings.KeyBindingPanelDescription); [BackgroundDependencyLoader(permitNulls: true)] private void load(RulesetStore rulesets, GlobalActionContainer global) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs index 6e018597be..c38c516f21 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingRow.cs @@ -20,6 +20,7 @@ using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Input.Bindings; +using osu.Game.Localisation; using osuTK; using osuTK.Graphics; using osuTK.Input; @@ -385,7 +386,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public CancelButton() { - Text = "Cancel"; + Text = CommonStrings.Cancel; Size = new Vector2(80, 20); } } @@ -394,7 +395,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public ClearButton() { - Text = "Clear"; + Text = CommonStrings.Clear; Size = new Vector2(80, 20); } } diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index d65684fd37..ef5ccae1a0 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -10,6 +10,7 @@ using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Rulesets; +using osu.Game.Localisation; using osuTK; namespace osu.Game.Overlays.Settings.Sections.Input @@ -64,7 +65,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input [BackgroundDependencyLoader] private void load() { - Text = "Reset all bindings in section"; + Text = InputSettingsStrings.ResetSectionButton; RelativeSizeAxes = Axes.X; Width = 0.5f; Anchor = Anchor.TopCentre; diff --git a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs index 81a4d7eccd..5246051a4a 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/RulesetBindingsSection.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Rulesets; @@ -15,7 +16,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Icon = OsuIcon.Hot }; - public override string Header => ruleset.Name; + public override LocalisableString Header => ruleset.Name; private readonly RulesetInfo ruleset; diff --git a/osu.Game/Overlays/Settings/Sections/InputSection.cs b/osu.Game/Overlays/Settings/Sections/InputSection.cs index 366f39388a..d282ba5318 100644 --- a/osu.Game/Overlays/Settings/Sections/InputSection.cs +++ b/osu.Game/Overlays/Settings/Sections/InputSection.cs @@ -11,6 +11,7 @@ using osu.Framework.Input.Handlers.Mouse; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Input; namespace osu.Game.Overlays.Settings.Sections @@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections { private readonly KeyBindingPanel keyConfig; - public override string Header => "Input"; + public override LocalisableString Header => InputSettingsStrings.InputSectionHeader; [Resolved] private GameHost host { get; set; } @@ -95,7 +96,7 @@ namespace osu.Game.Overlays.Settings.Sections { new SettingsCheckbox { - LabelText = "Enabled", + LabelText = CommonStrings.Enabled, Current = handler.Enabled }, }; From 7adf2bb64c3be39f920cb074781fe032af3d0e9b Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 10:48:29 +0800 Subject: [PATCH 167/961] Add UserInterfaceStrings --- osu.Game/Localisation/UserInterfaceStrings.cs | 114 ++++++++++++++++++ .../Sections/UserInterface/GeneralSettings.cs | 11 +- .../UserInterface/MainMenuSettings.cs | 17 ++- .../UserInterface/SongSelectSettings.cs | 15 +-- .../Settings/Sections/UserInterfaceSection.cs | 4 +- 5 files changed, 139 insertions(+), 22 deletions(-) create mode 100644 osu.Game/Localisation/UserInterfaceStrings.cs diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs new file mode 100644 index 0000000000..18a9257732 --- /dev/null +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -0,0 +1,114 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class UserInterfaceStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.UserInterface"; + + /// + /// "User Interface" + /// + public static LocalisableString UserInterfaceSectionHeader => new TranslatableString(getKey(@"user_interface_section_header"), @"User Interface"); + + /// + /// "General" + /// + public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General"); + + /// + /// "Rotate cursor when dragging" + /// + public static LocalisableString CursorRotation => new TranslatableString(getKey(@"cursor_rotation"), @"Rotate cursor when dragging"); + + /// + /// "Menu cursor size" + /// + public static LocalisableString MenuCursorSize => new TranslatableString(getKey(@"menu_cursor_size"), @"Menu cursor size"); + + /// + /// "Parallax" + /// + public static LocalisableString Parallax => new TranslatableString(getKey(@"parallax"), @"Parallax"); + + /// + /// "Hold-to-confirm activation time" + /// + public static LocalisableString HoldActivationDelay => new TranslatableString(getKey(@"hold_activation_delay"), @"Hold-to-confirm activation time"); + + /// + /// "Main Menu" + /// + public static LocalisableString MainMenuHeader => new TranslatableString(getKey(@"main_menu_header"), @"Main Menu"); + + /// + /// "Interface voices" + /// + public static LocalisableString InterfaceVoices => new TranslatableString(getKey(@"interface_voices"), @"Interface voices"); + + /// + /// "osu! music theme" + /// + public static LocalisableString OsuMusicTheme => new TranslatableString(getKey(@"osu_music_theme"), @"osu! music theme"); + + /// + /// "Intro sequence" + /// + public static LocalisableString IntroSequence => new TranslatableString(getKey(@"intro_sequence"), @"Intro sequence"); + + /// + /// "Background source" + /// + public static LocalisableString BackgroundSource => new TranslatableString(getKey(@"background_source"), @"Background source"); + + /// + /// "Seasonal backgrounds" + /// + public static LocalisableString SeasonalBackgrounds => new TranslatableString(getKey(@"seasonal_backgrounds"), @"Seasonal backgrounds"); + + /// + /// "Changes to this setting will only apply with an active osu!supporter tag." + /// + public static LocalisableString NotSupporterNote => new TranslatableString(getKey(@"not_supporter_note"), @"Changes to this setting will only apply with an active osu!supporter tag."); + + /// + /// "Song Select" + /// + public static LocalisableString SoneSelectHeader => new TranslatableString(getKey(@"song_select_header"), @"Song Select"); + + /// + /// "Right mouse drag to absolute scroll" + /// + public static LocalisableString RightMouseScroll => new TranslatableString(getKey(@"right_mouse_scroll"), @"Right mouse drag to absolute scroll"); + + /// + /// "Show converted beatmaps" + /// + public static LocalisableString ShowConvertedBeatmaps => new TranslatableString(getKey(@"show_converted_beatmaps"), @"Show converted beatmaps"); + + /// + /// "Display beatmaps from" + /// + public static LocalisableString StarsMinimum => new TranslatableString(getKey(@"stars_minimum"), @"Display beatmaps from"); + + /// + /// "up to" + /// + public static LocalisableString StarsMaximum => new TranslatableString(getKey(@"stars_maximum"), @"up to"); + + /// + /// "Random selection algorithm" + /// + public static LocalisableString RandomSelectionAlgorithm => new TranslatableString(getKey(@"random_selection_algorithm"), @"Random selection algorithm"); + + /// + /// "no limit" + /// + public static LocalisableString NoLimit => new TranslatableString(getKey(@"no_limit"), @"no limit"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index 4b26645ef3..b26363a9da 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -6,12 +6,13 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.UserInterface { public class GeneralSettings : SettingsSubsection { - protected override LocalisableString Header => "General"; + protected override LocalisableString Header => UserInterfaceStrings.GeneralHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -20,23 +21,23 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { new SettingsCheckbox { - LabelText = "Rotate cursor when dragging", + LabelText = UserInterfaceStrings.CursorRotation, Current = config.GetBindable(OsuSetting.CursorRotation) }, new SettingsSlider { - LabelText = "Menu cursor size", + LabelText = UserInterfaceStrings.MenuCursorSize, Current = config.GetBindable(OsuSetting.MenuCursorSize), KeyboardStep = 0.01f }, new SettingsCheckbox { - LabelText = "Parallax", + LabelText = UserInterfaceStrings.Parallax, Current = config.GetBindable(OsuSetting.MenuParallax) }, new SettingsSlider { - LabelText = "Hold-to-confirm activation time", + LabelText = UserInterfaceStrings.HoldActivationDelay, Current = config.GetBindable(OsuSetting.UIHoldActivationDelay), KeyboardStep = 50 }, diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 81bbcbb54a..976893bf0a 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Online.API; using osu.Game.Users; @@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { public class MainMenuSettings : SettingsSubsection { - protected override LocalisableString Header => "Main Menu"; + protected override LocalisableString Header => UserInterfaceStrings.MainMenuHeader; private IBindable user; @@ -28,27 +29,27 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { new SettingsCheckbox { - LabelText = "Interface voices", + LabelText = UserInterfaceStrings.InterfaceVoices, Current = config.GetBindable(OsuSetting.MenuVoice) }, new SettingsCheckbox { - LabelText = "osu! music theme", + LabelText = UserInterfaceStrings.OsuMusicTheme, Current = config.GetBindable(OsuSetting.MenuMusic) }, new SettingsEnumDropdown { - LabelText = "Intro sequence", + LabelText = UserInterfaceStrings.IntroSequence, Current = config.GetBindable(OsuSetting.IntroSequence), }, backgroundSourceDropdown = new SettingsEnumDropdown { - LabelText = "Background source", + LabelText = UserInterfaceStrings.BackgroundSource, Current = config.GetBindable(OsuSetting.MenuBackgroundSource), }, new SettingsEnumDropdown { - LabelText = "Seasonal backgrounds", + LabelText = UserInterfaceStrings.SeasonalBackgrounds, Current = config.GetBindable(OsuSetting.SeasonalBackgroundMode), } }; @@ -60,9 +61,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface user.BindValueChanged(u => { - const string not_supporter_note = "Changes to this setting will only apply with an active osu!supporter tag."; - - backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? not_supporter_note : string.Empty; + backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : string.Empty; }, true); } } diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 587155eb0d..8596cecbb8 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.UserInterface { @@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface private Bindable minStars; private Bindable maxStars; - protected override LocalisableString Header => "Song Select"; + protected override LocalisableString Header => UserInterfaceStrings.SoneSelectHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -31,31 +32,31 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface { new SettingsCheckbox { - LabelText = "Right mouse drag to absolute scroll", + LabelText = UserInterfaceStrings.RightMouseScroll, Current = config.GetBindable(OsuSetting.SongSelectRightMouseScroll), }, new SettingsCheckbox { - LabelText = "Show converted beatmaps", + LabelText = UserInterfaceStrings.ShowConvertedBeatmaps, Current = config.GetBindable(OsuSetting.ShowConvertedBeatmaps), }, new SettingsSlider { - LabelText = "Display beatmaps from", + LabelText = UserInterfaceStrings.StarsMinimum, Current = config.GetBindable(OsuSetting.DisplayStarsMinimum), KeyboardStep = 0.1f, Keywords = new[] { "minimum", "maximum", "star", "difficulty" } }, new SettingsSlider { - LabelText = "up to", + LabelText = UserInterfaceStrings.StarsMaximum, Current = config.GetBindable(OsuSetting.DisplayStarsMaximum), KeyboardStep = 0.1f, Keywords = new[] { "minimum", "maximum", "star", "difficulty" } }, new SettingsEnumDropdown { - LabelText = "Random selection algorithm", + LabelText = UserInterfaceStrings.RandomSelectionAlgorithm, Current = config.GetBindable(OsuSetting.RandomSelectAlgorithm), } }; @@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface private class MaximumStarsSlider : StarsSlider { - public override LocalisableString TooltipText => Current.IsDefault ? "no limit" : base.TooltipText; + public override LocalisableString TooltipText => Current.IsDefault ? UserInterfaceStrings.NoLimit : base.TooltipText; } private class StarsSlider : OsuSliderBar diff --git a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs index 718fea5f2b..6228c4c99a 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterfaceSection.cs @@ -3,13 +3,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.UserInterface; namespace osu.Game.Overlays.Settings.Sections { public class UserInterfaceSection : SettingsSection { - public override string Header => "User Interface"; + public override LocalisableString Header => UserInterfaceStrings.UserInterfaceSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From 31ffaf15d4866275f1c86c0dbecd67af5eba59ff Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 11:11:22 +0800 Subject: [PATCH 168/961] Add GameplaySettingsStrings --- .../Localisation/GameplaySettingsStrings.cs | 95 +++++++++++++++++++ .../Sections/Gameplay/GeneralSettings.cs | 27 +++--- .../Sections/Gameplay/ModsSettings.cs | 5 +- .../Settings/Sections/GameplaySection.cs | 4 +- 4 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 osu.Game/Localisation/GameplaySettingsStrings.cs diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs new file mode 100644 index 0000000000..172387bbb8 --- /dev/null +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -0,0 +1,95 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class GameplaySettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.GameplaySettings"; + + /// + /// "Gameplay" + /// + public static LocalisableString GameplaySectionHeader => new TranslatableString(getKey(@"gameplay_section_header"), @"Gameplay"); + + /// + /// "General" + /// + public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General"); + + /// + /// "Background dim" + /// + public static LocalisableString Dim => new TranslatableString(getKey(@"dim"), @"Background dim"); + + /// + /// "Background blur" + /// + public static LocalisableString Blur => new TranslatableString(getKey(@"blur"), @"Background blur"); + + /// + /// "Lighten playfield during breaks" + /// + public static LocalisableString LightenDuringBreaks => new TranslatableString(getKey(@"lighten_during_breaks"), @"Lighten playfield during breaks"); + + /// + /// "HUD overlay visibility mode" + /// + public static LocalisableString HUDVisibilityMode => new TranslatableString(getKey(@"hud_visibility_mode"), @"HUD overlay visibility mode"); + + /// + /// "Show difficulty graph on progress bar" + /// + public static LocalisableString ShowProgressGraph => new TranslatableString(getKey(@"show_progress_graph"), @"Show difficulty graph on progress bar"); + + /// + /// "Show health display even when you can't fail" + /// + public static LocalisableString ShowHealthDisplayWhenCantFail => new TranslatableString(getKey(@"show_health_display_when_cant_fail"), @"Show health display even when you can't fail"); + + /// + /// "Fade playfield to red when health is low" + /// + public static LocalisableString FadePlayfieldWhenHealthLow => new TranslatableString(getKey(@"fade_playfield_when_health_low"), @"Fade playfield to red when health is low"); + + /// + /// "Always show key overlay" + /// + public static LocalisableString KeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay"); + + /// + /// "Positional hitsounds" + /// + public static LocalisableString PositionalHitsounds => new TranslatableString(getKey(@"positional_hitsounds"), @"Positional hitsounds"); + + /// + /// "Always play first combo break sound" + /// + public static LocalisableString AlwaysPlayFirstComboBreak => new TranslatableString(getKey(@"always_play_first_combo_break"), @"Always play first combo break sound"); + + /// + /// "Score display mode" + /// + public static LocalisableString ScoreDisplayMode => new TranslatableString(getKey(@"score_display_mode"), @"Score display mode"); + + /// + /// "Disable Windows key during gameplay" + /// + public static LocalisableString DisableWinKey => new TranslatableString(getKey(@"disable_win_key"), @"Disable Windows key during gameplay"); + + /// + /// "Mods" + /// + public static LocalisableString ModsHeader => new TranslatableString(getKey(@"mods_header"), @"Mods"); + + /// + /// "Increase visibility of first object when visual impairment mods are enabled" + /// + public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled"); + + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 353292606f..efb586fdca 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -6,13 +6,14 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Rulesets.Scoring; namespace osu.Game.Overlays.Settings.Sections.Gameplay { public class GeneralSettings : SettingsSubsection { - protected override LocalisableString Header => "General"; + protected override LocalisableString Header => GameplaySettingsStrings.GeneralHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -21,62 +22,62 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { new SettingsSlider { - LabelText = "Background dim", + LabelText = GameplaySettingsStrings.Dim, Current = config.GetBindable(OsuSetting.DimLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = "Background blur", + LabelText = GameplaySettingsStrings.Blur, Current = config.GetBindable(OsuSetting.BlurLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsCheckbox { - LabelText = "Lighten playfield during breaks", + LabelText = GameplaySettingsStrings.LightenDuringBreaks, Current = config.GetBindable(OsuSetting.LightenDuringBreaks) }, new SettingsEnumDropdown { - LabelText = "HUD overlay visibility mode", + LabelText = GameplaySettingsStrings.HUDVisibilityMode, Current = config.GetBindable(OsuSetting.HUDVisibilityMode) }, new SettingsCheckbox { - LabelText = "Show difficulty graph on progress bar", + LabelText = GameplaySettingsStrings.ShowProgressGraph, Current = config.GetBindable(OsuSetting.ShowProgressGraph) }, new SettingsCheckbox { - LabelText = "Show health display even when you can't fail", + LabelText = GameplaySettingsStrings.ShowHealthDisplayWhenCantFail, Current = config.GetBindable(OsuSetting.ShowHealthDisplayWhenCantFail), Keywords = new[] { "hp", "bar" } }, new SettingsCheckbox { - LabelText = "Fade playfield to red when health is low", + LabelText = GameplaySettingsStrings.FadePlayfieldWhenHealthLow, Current = config.GetBindable(OsuSetting.FadePlayfieldWhenHealthLow), }, new SettingsCheckbox { - LabelText = "Always show key overlay", + LabelText = GameplaySettingsStrings.KeyOverlay, Current = config.GetBindable(OsuSetting.KeyOverlay) }, new SettingsCheckbox { - LabelText = "Positional hitsounds", + LabelText = GameplaySettingsStrings.PositionalHitsounds, Current = config.GetBindable(OsuSetting.PositionalHitSounds) }, new SettingsCheckbox { - LabelText = "Always play first combo break sound", + LabelText = GameplaySettingsStrings.AlwaysPlayFirstComboBreak, Current = config.GetBindable(OsuSetting.AlwaysPlayFirstComboBreak) }, new SettingsEnumDropdown { - LabelText = "Score display mode", + LabelText = GameplaySettingsStrings.ScoreDisplayMode, Current = config.GetBindable(OsuSetting.ScoreDisplayMode), Keywords = new[] { "scoring" } }, @@ -86,7 +87,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { Add(new SettingsCheckbox { - LabelText = "Disable Windows key during gameplay", + LabelText = GameplaySettingsStrings.DisableWinKey, Current = config.GetBindable(OsuSetting.GameplayDisableWinKey) }); } diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs index ec9ddde2da..dfa060e8d5 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/ModsSettings.cs @@ -6,12 +6,13 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Gameplay { public class ModsSettings : SettingsSubsection { - protected override LocalisableString Header => "Mods"; + protected override LocalisableString Header => GameplaySettingsStrings.ModsHeader; public override IEnumerable FilterTerms => base.FilterTerms.Concat(new[] { "mod" }); @@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { new SettingsCheckbox { - LabelText = "Increase visibility of first object when visual impairment mods are enabled", + LabelText = GameplaySettingsStrings.IncreaseFirstObjectVisibility, Current = config.GetBindable(OsuSetting.IncreaseFirstObjectVisibility), }, }; diff --git a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs index acb94a6a01..42d9d48d73 100644 --- a/osu.Game/Overlays/Settings/Sections/GameplaySection.cs +++ b/osu.Game/Overlays/Settings/Sections/GameplaySection.cs @@ -9,12 +9,14 @@ using osu.Game.Rulesets; using System.Linq; using osu.Framework.Graphics.Sprites; using osu.Framework.Logging; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections { public class GameplaySection : SettingsSection { - public override string Header => "Gameplay"; + public override LocalisableString Header => GameplaySettingsStrings.GameplaySectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From 61502e977afcaa4731fb8d6f2b3d2f6c46eb11b8 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 11:40:22 +0800 Subject: [PATCH 169/961] Add SkinSettingsStrings --- osu.Game/Localisation/SkinSettingsStrings.cs | 54 +++++++++++++++++++ .../Overlays/Settings/Sections/SkinSection.cs | 17 +++--- 2 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Localisation/SkinSettingsStrings.cs diff --git a/osu.Game/Localisation/SkinSettingsStrings.cs b/osu.Game/Localisation/SkinSettingsStrings.cs new file mode 100644 index 0000000000..848c01b93a --- /dev/null +++ b/osu.Game/Localisation/SkinSettingsStrings.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class SkinSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SkinSettings"; + + /// + /// "Skin" + /// + public static LocalisableString SkinSectionHeader => new TranslatableString(getKey(@"skin_section_header"), @"Skin"); + + /// + /// "Skin layout editor" + /// + public static LocalisableString SkinLayoutEditor => new TranslatableString(getKey(@"skin_layout_editor"), @"Skin layout editor"); + + /// + /// "Gameplay cursor size" + /// + public static LocalisableString CursorSize => new TranslatableString(getKey(@"cursor_size"), @"Gameplay cursor size"); + + /// + /// "Adjust gameplay cursor size based on current beatmap" + /// + public static LocalisableString AutoCursorSize => new TranslatableString(getKey(@"auto_cursor_size"), @"Adjust gameplay cursor size based on current beatmap"); + + /// + /// "Beatmap skins" + /// + public static LocalisableString BeatmapSkins => new TranslatableString(getKey(@"beatmap_skins"), @"Beatmap skins"); + + /// + /// "Beatmap colours" + /// + public static LocalisableString BeatmapColours => new TranslatableString(getKey(@"beatmap_colours"), @"Beatmap colours"); + + /// + /// "Beatmap hitsounds" + /// + public static LocalisableString BeatmapHitsounds => new TranslatableString(getKey(@"beatmap_hitsounds"), @"Beatmap hitsounds"); + + /// + /// "Export selected skin" + /// + public static LocalisableString ExportSkinButton => new TranslatableString(getKey(@"export_skin_button"), @"Export selected skin"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 9f3543d059..007302c584 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -13,6 +13,7 @@ using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Skinning; using osu.Game.Skinning.Editor; using osuTK; @@ -23,7 +24,7 @@ namespace osu.Game.Overlays.Settings.Sections { private SkinSettingsDropdown skinDropdown; - public override string Header => "Skin"; + public override LocalisableString Header => SkinSettingsStrings.SkinSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { @@ -69,34 +70,34 @@ namespace osu.Game.Overlays.Settings.Sections skinDropdown = new SkinSettingsDropdown(), new SettingsButton { - Text = "Skin layout editor", + Text = SkinSettingsStrings.SkinLayoutEditor, Action = () => skinEditor?.Toggle(), }, new ExportSkinButton(), new SettingsSlider { - LabelText = "Gameplay cursor size", + LabelText = SkinSettingsStrings.CursorSize, Current = config.GetBindable(OsuSetting.GameplayCursorSize), KeyboardStep = 0.01f }, new SettingsCheckbox { - LabelText = "Adjust gameplay cursor size based on current beatmap", + LabelText = SkinSettingsStrings.AutoCursorSize, Current = config.GetBindable(OsuSetting.AutoCursorSize) }, new SettingsCheckbox { - LabelText = "Beatmap skins", + LabelText = SkinSettingsStrings.BeatmapSkins, Current = config.GetBindable(OsuSetting.BeatmapSkins) }, new SettingsCheckbox { - LabelText = "Beatmap colours", + LabelText = SkinSettingsStrings.BeatmapColours, Current = config.GetBindable(OsuSetting.BeatmapColours) }, new SettingsCheckbox { - LabelText = "Beatmap hitsounds", + LabelText = SkinSettingsStrings.BeatmapHitsounds, Current = config.GetBindable(OsuSetting.BeatmapHitsounds) }, }; @@ -200,7 +201,7 @@ namespace osu.Game.Overlays.Settings.Sections [BackgroundDependencyLoader] private void load() { - Text = "Export selected skin"; + Text = SkinSettingsStrings.ExportSkinButton; Action = export; currentSkin = skins.CurrentSkin.GetBoundCopy(); From 9d391ad13817df8a81c5733fa7ee4f759852e095 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 11:57:51 +0800 Subject: [PATCH 170/961] Add OnlineSettingsStrings --- .../Localisation/OnlineSettingsStrings.cs | 69 +++++++++++++++++++ .../Online/AlertsAndPrivacySettings.cs | 7 +- .../Sections/Online/IntegrationSettings.cs | 5 +- .../Settings/Sections/Online/WebSettings.cs | 11 +-- .../Settings/Sections/OnlineSection.cs | 4 +- 5 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 osu.Game/Localisation/OnlineSettingsStrings.cs diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs new file mode 100644 index 0000000000..0ef98a720c --- /dev/null +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -0,0 +1,69 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class OnlineSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.OnlineSettings"; + + /// + /// "Online" + /// + public static LocalisableString OnlineSectionHeader => new TranslatableString(getKey(@"online_section_header"), @"Online"); + + /// + /// "Alerts and Privacy" + /// + public static LocalisableString AlertsAndPrivacyHeader => new TranslatableString(getKey(@"alerts_and_privacy_header"), @"Alerts and Privacy"); + + /// + /// "Show a notification when someone mentions your name" + /// + public static LocalisableString NotifyOnMentioned => new TranslatableString(getKey(@"notify_on_mentioned"), @"Show a notification when someone mentions your name"); + + /// + /// "Show a notification when you receive a private message" + /// + public static LocalisableString NotifyOnPM => new TranslatableString(getKey(@"notify_on_pm"), @"Show a notification when you receive a private message"); + + /// + /// "Integrations" + /// + public static LocalisableString IntegrationHeader => new TranslatableString(getKey(@"integration_header"), @"Integrations"); + + /// + /// "Discord Rich Presence" + /// + public static LocalisableString DiscordRichPresence => new TranslatableString(getKey(@"discord_rich_presence"), @"Discord Rich Presence"); + + /// + /// "Web" + /// + public static LocalisableString WebHeader => new TranslatableString(getKey(@"web_header"), @"Web"); + + /// + /// "Warn about opening external links" + /// + public static LocalisableString ExternalLinkWarning => new TranslatableString(getKey(@"external_link_warning"), @"Warn about opening external links"); + + /// + /// "Prefer downloads without video" + /// + public static LocalisableString PreferNoVideo => new TranslatableString(getKey(@"prefer_no_video"), @"Prefer downloads without video"); + + /// + /// "Automatically download beatmaps when spectating" + /// + public static LocalisableString AutomaticallyDownload => new TranslatableString(getKey(@"automatically_download"), @"Automatically download beatmaps when spectating"); + + /// + /// "Show explicit content in search results" + /// + public static LocalisableString ShowExplicitContent => new TranslatableString(getKey(@"show_explicit_content"), @"Show explicit content in search results"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 3a2de2ee36..1728b565c2 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -5,12 +5,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { public class AlertsAndPrivacySettings : SettingsSubsection { - protected override LocalisableString Header => "Alerts and Privacy"; + protected override LocalisableString Header => OnlineSettingsStrings.AlertsAndPrivacyHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -19,12 +20,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online { new SettingsCheckbox { - LabelText = "Show a notification when someone mentions your name", + LabelText = OnlineSettingsStrings.NotifyOnMentioned, Current = config.GetBindable(OsuSetting.NotifyOnUsernameMentioned) }, new SettingsCheckbox { - LabelText = "Show a notification when you receive a private message", + LabelText = OnlineSettingsStrings.NotifyOnPM, Current = config.GetBindable(OsuSetting.NotifyOnPrivateMessage) }, }; diff --git a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs index f2012f0d9c..f2a516feef 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs @@ -5,12 +5,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { public class IntegrationSettings : SettingsSubsection { - protected override LocalisableString Header => "Integrations"; + protected override LocalisableString Header => OnlineSettingsStrings.IntegrationHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -19,7 +20,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online { new SettingsEnumDropdown { - LabelText = "Discord Rich Presence", + LabelText = OnlineSettingsStrings.DiscordRichPresence, Current = config.GetBindable(OsuSetting.DiscordRichPresence) } }; diff --git a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs index 89e7b096f3..4200ddda3d 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs @@ -5,12 +5,13 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Configuration; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Online { public class WebSettings : SettingsSubsection { - protected override LocalisableString Header => "Web"; + protected override LocalisableString Header => OnlineSettingsStrings.WebHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) @@ -19,24 +20,24 @@ namespace osu.Game.Overlays.Settings.Sections.Online { new SettingsCheckbox { - LabelText = "Warn about opening external links", + LabelText = OnlineSettingsStrings.ExternalLinkWarning, Current = config.GetBindable(OsuSetting.ExternalLinkWarning) }, new SettingsCheckbox { - LabelText = "Prefer downloads without video", + LabelText = OnlineSettingsStrings.PreferNoVideo, Keywords = new[] { "no-video" }, Current = config.GetBindable(OsuSetting.PreferNoVideo) }, new SettingsCheckbox { - LabelText = "Automatically download beatmaps when spectating", + LabelText = OnlineSettingsStrings.AutomaticallyDownload, Keywords = new[] { "spectator" }, Current = config.GetBindable(OsuSetting.AutomaticallyDownloadWhenSpectating), }, new SettingsCheckbox { - LabelText = "Show explicit content in search results", + LabelText = OnlineSettingsStrings.ShowExplicitContent, Keywords = new[] { "nsfw", "18+", "offensive" }, Current = config.GetBindable(OsuSetting.ShowOnlineExplicitContent), } diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index 680d11f7da..8b523b90b9 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -3,13 +3,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Online; namespace osu.Game.Overlays.Settings.Sections { public class OnlineSection : SettingsSection { - public override string Header => "Online"; + public override LocalisableString Header => OnlineSettingsStrings.OnlineSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From ac52b891489afc591ee4d5b08c54547c5c43de52 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 12:26:42 +0800 Subject: [PATCH 171/961] Add Maintenance and Debug SettingsStrings --- osu.Game/Localisation/DebugSettingsStrings.cs | 49 ++++++++++++ .../MaintenanceSettingsStrings.cs | 74 +++++++++++++++++++ .../Sections/Debug/GeneralSettings.cs | 9 ++- .../Settings/Sections/Debug/MemorySettings.cs | 5 +- .../Settings/Sections/DebugSection.cs | 4 +- .../Maintenance/DirectorySelectScreen.cs | 3 +- .../Sections/Maintenance/GeneralSettings.cs | 21 +++--- .../Settings/Sections/MaintenanceSection.cs | 4 +- 8 files changed, 150 insertions(+), 19 deletions(-) create mode 100644 osu.Game/Localisation/DebugSettingsStrings.cs create mode 100644 osu.Game/Localisation/MaintenanceSettingsStrings.cs diff --git a/osu.Game/Localisation/DebugSettingsStrings.cs b/osu.Game/Localisation/DebugSettingsStrings.cs new file mode 100644 index 0000000000..dd21739096 --- /dev/null +++ b/osu.Game/Localisation/DebugSettingsStrings.cs @@ -0,0 +1,49 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class DebugSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.DebugSettings"; + + /// + /// "Debug" + /// + public static LocalisableString DebugSectionHeader => new TranslatableString(getKey(@"debug_section_header"), @"Debug"); + + /// + /// "General" + /// + public static LocalisableString GeneralHeader => new TranslatableString(getKey(@"general_header"), @"General"); + + /// + /// "Show log overlay" + /// + public static LocalisableString ShowLogOverlay => new TranslatableString(getKey(@"show_log_overlay"), @"Show log overlay"); + + /// + /// "Bypass front-to-back render pass" + /// + public static LocalisableString BypassFrontToBackPass => new TranslatableString(getKey(@"bypass_front_to_back_pass"), @"Bypass front-to-back render pass"); + + /// + /// "Import files" + /// + public static LocalisableString ImportFiles => new TranslatableString(getKey(@"import_files"), @"Import files"); + + /// + /// "Memory" + /// + public static LocalisableString MemoryHeader => new TranslatableString(getKey(@"memory_header"), @"Memory"); + + /// + /// "Clear all caches" + /// + public static LocalisableString ClearAllCaches => new TranslatableString(getKey(@"clear_all_caches"), @"Clear all caches"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/MaintenanceSettingsStrings.cs b/osu.Game/Localisation/MaintenanceSettingsStrings.cs new file mode 100644 index 0000000000..a0e1a9ddab --- /dev/null +++ b/osu.Game/Localisation/MaintenanceSettingsStrings.cs @@ -0,0 +1,74 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class MaintenanceSettingsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.MaintenanceSettings"; + + /// + /// "Maintenance" + /// + public static LocalisableString MaintenanceSectionHeader => new TranslatableString(getKey(@"maintenance_section_header"), @"Maintenance"); + + /// + /// "Select directory" + /// + public static LocalisableString SelectDirectory => new TranslatableString(getKey(@"select_directory"), @"Select directory"); + + /// + /// "Import beatmaps from stable" + /// + public static LocalisableString ImportBeatmapsFromStable => new TranslatableString(getKey(@"import_beatmaps_from_stable"), @"Import beatmaps from stable"); + + /// + /// "Delete ALL beatmaps" + /// + public static LocalisableString DeleteAllBeatmaps => new TranslatableString(getKey(@"delete_all_beatmaps"), @"Delete ALL beatmaps"); + + /// + /// "Import scores from stable" + /// + public static LocalisableString ImportScoresFromStable => new TranslatableString(getKey(@"import_scores_from_stable"), @"Import scores from stable"); + + /// + /// "Delete ALL scores" + /// + public static LocalisableString DeleteAllScores => new TranslatableString(getKey(@"delete_all_scores"), @"Delete ALL scores"); + + /// + /// "Import skins from stable" + /// + public static LocalisableString ImportSkinsFromStable => new TranslatableString(getKey(@"import_skins_from_stable"), @"Import skins from stable"); + + /// + /// "Delete ALL skins" + /// + public static LocalisableString DeleteAllSkins => new TranslatableString(getKey(@"delete_all_skins"), @"Delete ALL skins"); + + /// + /// "Import collections from stable" + /// + public static LocalisableString ImportCollectionsFromStable => new TranslatableString(getKey(@"import_collections_from_stable"), @"Import collections from stable"); + + /// + /// "Delete ALL collections" + /// + public static LocalisableString DeleteAllCollections => new TranslatableString(getKey(@"delete_all_collections"), @"Delete ALL collections"); + + /// + /// "Restore all hidden difficulties" + /// + public static LocalisableString RestoreAllHiddenDifficulties => new TranslatableString(getKey(@"restore_all_hidden_difficulties"), @"Restore all hidden difficulties"); + + /// + /// "Restore all recently deleted beatmaps" + /// + public static LocalisableString RestoreAllRecentlyDeletedBeatmaps => new TranslatableString(getKey(@"restore_all_recently_deleted_beatmaps"), @"Restore all recently deleted beatmaps"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs index 2b868cab85..25e20911b8 100644 --- a/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Debug/GeneralSettings.cs @@ -6,13 +6,14 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Framework.Screens; +using osu.Game.Localisation; using osu.Game.Screens.Import; namespace osu.Game.Overlays.Settings.Sections.Debug { public class GeneralSettings : SettingsSubsection { - protected override LocalisableString Header => "General"; + protected override LocalisableString Header => DebugSettingsStrings.GeneralHeader; [BackgroundDependencyLoader(true)] private void load(FrameworkDebugConfigManager config, FrameworkConfigManager frameworkConfig, OsuGame game) @@ -21,18 +22,18 @@ namespace osu.Game.Overlays.Settings.Sections.Debug { new SettingsCheckbox { - LabelText = "Show log overlay", + LabelText = DebugSettingsStrings.ShowLogOverlay, Current = frameworkConfig.GetBindable(FrameworkSetting.ShowLogOverlay) }, new SettingsCheckbox { - LabelText = "Bypass front-to-back render pass", + LabelText = DebugSettingsStrings.BypassFrontToBackPass, Current = config.GetBindable(DebugSetting.BypassFrontToBackPass) } }; Add(new SettingsButton { - Text = "Import files", + Text = DebugSettingsStrings.ImportFiles, Action = () => game?.PerformFromScreen(menu => menu.Push(new FileImportScreen())) }); } diff --git a/osu.Game/Overlays/Settings/Sections/Debug/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/Debug/MemorySettings.cs index bf7fb351c0..07fb0aca5a 100644 --- a/osu.Game/Overlays/Settings/Sections/Debug/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Debug/MemorySettings.cs @@ -6,12 +6,13 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Framework.Platform; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Debug { public class MemorySettings : SettingsSubsection { - protected override LocalisableString Header => "Memory"; + protected override LocalisableString Header => DebugSettingsStrings.MemoryHeader; [BackgroundDependencyLoader] private void load(FrameworkDebugConfigManager config, GameHost host) @@ -20,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Debug { new SettingsButton { - Text = "Clear all caches", + Text = DebugSettingsStrings.ClearAllCaches, Action = host.Collect }, }; diff --git a/osu.Game/Overlays/Settings/Sections/DebugSection.cs b/osu.Game/Overlays/Settings/Sections/DebugSection.cs index 44d4088972..aa85ec920c 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSection.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSection.cs @@ -3,13 +3,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Debug; namespace osu.Game.Overlays.Settings.Sections { public class DebugSection : SettingsSection { - public override string Header => "Debug"; + public override LocalisableString Header => DebugSettingsStrings.DebugSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index 5392ba5d93..e509cac2f1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -14,6 +14,7 @@ using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Graphics.Containers; +using osu.Game.Localisation; namespace osu.Game.Overlays.Settings.Sections.Maintenance { @@ -104,7 +105,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Origin = Anchor.Centre, Width = 300, Margin = new MarginPadding(10), - Text = "Select directory", + Text = MaintenanceSettingsStrings.SelectDirectory, Action = () => OnSelection(directorySelector.CurrentPath.Value) }, } diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs index b9a408b1f8..803c8332c1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -11,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Collections; using osu.Game.Database; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Scoring; using osu.Game.Skinning; @@ -37,7 +38,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importBeatmapsButton = new SettingsButton { - Text = "Import beatmaps from stable", + Text = MaintenanceSettingsStrings.ImportBeatmapsFromStable, Action = () => { importBeatmapsButton.Enabled.Value = false; @@ -48,7 +49,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Add(deleteBeatmapsButton = new DangerousSettingsButton { - Text = "Delete ALL beatmaps", + Text = MaintenanceSettingsStrings.DeleteAllBeatmaps, Action = () => { dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => @@ -63,7 +64,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importScoresButton = new SettingsButton { - Text = "Import scores from stable", + Text = MaintenanceSettingsStrings.ImportScoresFromStable, Action = () => { importScoresButton.Enabled.Value = false; @@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Add(deleteScoresButton = new DangerousSettingsButton { - Text = "Delete ALL scores", + Text = MaintenanceSettingsStrings.DeleteAllScores, Action = () => { dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => @@ -89,7 +90,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importSkinsButton = new SettingsButton { - Text = "Import skins from stable", + Text = MaintenanceSettingsStrings.ImportSkinsFromStable, Action = () => { importSkinsButton.Enabled.Value = false; @@ -100,7 +101,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Add(deleteSkinsButton = new DangerousSettingsButton { - Text = "Delete ALL skins", + Text = MaintenanceSettingsStrings.DeleteAllSkins, Action = () => { dialogOverlay?.Push(new DeleteAllBeatmapsDialog(() => @@ -117,7 +118,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { Add(importCollectionsButton = new SettingsButton { - Text = "Import collections from stable", + Text = MaintenanceSettingsStrings.ImportCollectionsFromStable, Action = () => { importCollectionsButton.Enabled.Value = false; @@ -128,7 +129,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance Add(new DangerousSettingsButton { - Text = "Delete ALL collections", + Text = MaintenanceSettingsStrings.DeleteAllCollections, Action = () => { dialogOverlay?.Push(new DeleteAllBeatmapsDialog(collectionManager.DeleteAll)); @@ -140,7 +141,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance { restoreButton = new SettingsButton { - Text = "Restore all hidden difficulties", + Text = MaintenanceSettingsStrings.RestoreAllHiddenDifficulties, Action = () => { restoreButton.Enabled.Value = false; @@ -153,7 +154,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance }, undeleteButton = new SettingsButton { - Text = "Restore all recently deleted beatmaps", + Text = MaintenanceSettingsStrings.RestoreAllRecentlyDeletedBeatmaps, Action = () => { undeleteButton.Enabled.Value = false; diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index 73c88b8e71..fa0c06167b 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -3,6 +3,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Localisation; using osu.Game.Overlays.Settings.Sections.Maintenance; using osuTK; @@ -10,7 +12,7 @@ namespace osu.Game.Overlays.Settings.Sections { public class MaintenanceSection : SettingsSection { - public override string Header => "Maintenance"; + public override LocalisableString Header => MaintenanceSettingsStrings.MaintenanceSectionHeader; public override Drawable CreateIcon() => new SpriteIcon { From 3f434c8474f19be27afc46254461bd5bfceeadfe Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Thu, 12 Aug 2021 13:42:16 +0800 Subject: [PATCH 172/961] Resolve code quality issue --- osu.Game/Localisation/GameplaySettingsStrings.cs | 1 - osu.sln.DotSettings | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 172387bbb8..4354272ab5 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -89,7 +89,6 @@ namespace osu.Game.Localisation /// public static LocalisableString IncreaseFirstObjectVisibility => new TranslatableString(getKey(@"increase_first_object_visibility"), @"Increase visibility of first object when visual impairment mods are enabled"); - private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 139ee02b96..d884ea31c5 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -304,6 +304,7 @@ AABB API BPM + FPS GC GL GLSL From 4d6101f4e5443438d95cd9c3df835b070e3aad78 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 14:56:58 +0900 Subject: [PATCH 173/961] Lease selected room while in match screen to avoid lounge potentially changing it --- .../OnlinePlay/Lounge/Components/RoomsContainer.cs | 4 +++- .../Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index d2253b2d2c..e951caa8a8 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -137,7 +137,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomFlow.Remove(toRemove); - selectedRoom.Value = null; + // selection may have a lease due to being in a sub screen. + if (!selectedRoom.Disabled) + selectedRoom.Value = null; } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 68bd3cd613..64c068e07e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -49,6 +50,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private RoomsContainer roomsContainer; + [CanBeNull] + private LeasedBindable selectionLease; + [BackgroundDependencyLoader] private void load() { @@ -144,6 +148,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { base.OnResuming(last); + Debug.Assert(selectionLease != null); + + selectionLease.Return(); + selectionLease = null; + if (selectedRoom.Value?.RoomID.Value == null) selectedRoom.Value = new Room(); @@ -210,7 +219,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected virtual void OpenNewRoom(Room room) { - selectedRoom.Value = room; + selectionLease = selectedRoom.BeginLease(false); + Debug.Assert(selectionLease != null); + selectionLease.Value = room; this.Push(CreateRoomSubScreen(room)); } From 524128441ede2f5ab66a5582ad2a3cd3a1650d08 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 15:03:05 +0900 Subject: [PATCH 174/961] Mark `PollingComponent` test as headless --- osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs index 2236f85b92..cc8503589d 100644 --- a/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs +++ b/osu.Game.Tests/Visual/Components/TestScenePollingComponent.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; +using osu.Framework.Testing; using osu.Game.Graphics.Sprites; using osu.Game.Online; using osuTK; @@ -15,6 +16,7 @@ using osuTK.Graphics; namespace osu.Game.Tests.Visual.Components { + [HeadlessTest] public class TestScenePollingComponent : OsuTestScene { private Container pollBox; From b713ba1bd441ae1cf5c7cfcbb9f51c3d0666abe1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 15:11:32 +0900 Subject: [PATCH 175/961] Add test coverage --- .../TestScenePlaylistsLoungeSubScreen.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index ecdb046203..aff0e7ba4b 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -62,6 +62,24 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("last room is not masked", () => checkRoomVisible(roomsContainer.Rooms[^1])); } + [Test] + public void TestEnteringRoomTakesLeaseOnSelection() + { + AddStep("add rooms", () => RoomManager.AddRooms(1)); + + AddAssert("selected room is not disabled", () => !OnlinePlayDependencies.SelectedRoom.Disabled); + + AddStep("select room", () => roomsContainer.Rooms[0].TriggerClick()); + AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null); + + AddStep("enter room", () => roomsContainer.Rooms[0].TriggerClick()); + + AddUntilStep("wait for match load", () => Stack.CurrentScreen is PlaylistsRoomSubScreen); + + AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null); + AddAssert("selected room is disabled", () => OnlinePlayDependencies.SelectedRoom.Disabled); + } + private bool checkRoomVisible(DrawableRoom room) => loungeScreen.ChildrenOfType().First().ScreenSpaceDrawQuad .Contains(room.ScreenSpaceDrawQuad.Centre); From f4591b01d7a4bb4f8e6ef8a9eb02bd47fe527a39 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 15:21:00 +0900 Subject: [PATCH 176/961] Add test step to show leaderboard in expanded state by default --- osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 17fe09f2c6..950f255a02 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -40,6 +40,7 @@ namespace osu.Game.Tests.Visual.Gameplay }); AddStep("add local player", () => createLeaderboardScore(playerScore, new User { Username = "You", Id = 3 }, true)); + AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } From 14fe2eea2a907f5cf2130aed4204e350500909e2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 6 Aug 2021 19:40:29 +0900 Subject: [PATCH 177/961] Add empty step to multiplayer TestEmpty() test --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 0ffa5209e3..7ff0368fc2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -87,6 +87,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public void TestEmpty() { // used to test the flow of multiplayer from visual tests. + AddStep("empty step", () => { }); } [Test] From 68dbbc17e88f89ca19cdd58436811e308f4411fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 16:17:14 +0900 Subject: [PATCH 178/961] Add support for automatic scrolling in gameplay leaderboard --- .../Gameplay/TestSceneGameplayLeaderboard.cs | 21 ++- .../Screens/Play/HUD/GameplayLeaderboard.cs | 131 ++++++++++++++++-- .../Play/HUD/GameplayLeaderboardScore.cs | 13 +- 3 files changed, 144 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 950f255a02..10257f9027 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -84,6 +84,23 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("add frenzibyte", () => createRandomScore(new User { Username = "frenzibyte", Id = 14210502 })); } + [Test] + public void TestMaxHeight() + { + int playerNumber = 1; + AddRepeatStep("add 3 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 3); + checkHeight(4); + + AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4); + checkHeight(8); + + AddRepeatStep("add 4 other players", () => createRandomScore(new User { Username = $"Player {playerNumber++}" }), 4); + checkHeight(8); + + void checkHeight(int panelCount) + => AddAssert($"leaderboard height is {panelCount} panels high", () => leaderboard.DrawHeight == (GameplayLeaderboardScore.PANEL_HEIGHT + leaderboard.Spacing) * panelCount); + } + private void createRandomScore(User user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user); private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false) @@ -94,9 +111,11 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestGameplayLeaderboard : GameplayLeaderboard { + public float Spacing => Flow.Spacing.Y; + public bool CheckPositionByUsername(string username, int? expectedPosition) { - var scoreItem = this.FirstOrDefault(i => i.User?.Username == username); + var scoreItem = Flow.FirstOrDefault(i => i.User?.Username == username); return scoreItem != null && scoreItem.ScorePosition == expectedPosition; } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 63cb4f89f5..807289d664 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -6,29 +6,58 @@ using System.Linq; using JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Caching; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.Containers; using osu.Game.Users; using osuTK; +using osuTK.Graphics; namespace osu.Game.Screens.Play.HUD { - public class GameplayLeaderboard : FillFlowContainer + public class GameplayLeaderboard : CompositeDrawable { + private readonly int maxPanels; private readonly Cached sorting = new Cached(); public Bindable Expanded = new Bindable(); - public GameplayLeaderboard() + protected readonly FillFlowContainer Flow; + + private bool requiresScroll; + private readonly OsuScrollContainer scroll; + + private GameplayLeaderboardScore trackedScore; + + /// + /// Create a new leaderboard. + /// + /// The maximum panels to show at once. Defines the maximum height of this component. + public GameplayLeaderboard(int maxPanels = 8) { + this.maxPanels = maxPanels; + Width = GameplayLeaderboardScore.EXTENDED_WIDTH + GameplayLeaderboardScore.SHEAR_WIDTH; - Direction = FillDirection.Vertical; - - Spacing = new Vector2(2.5f); - - LayoutDuration = 250; - LayoutEasing = Easing.OutQuint; + InternalChildren = new Drawable[] + { + scroll = new ManualScrollScrollContainer + { + RelativeSizeAxes = Axes.Both, + Child = Flow = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + X = GameplayLeaderboardScore.SHEAR_WIDTH, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(2.5f), + LayoutDuration = 450, + LayoutEasing = Easing.OutQuint, + } + } + }; } protected override void LoadComplete() @@ -50,22 +79,83 @@ namespace osu.Game.Screens.Play.HUD { var drawable = CreateLeaderboardScoreDrawable(user, isTracked); + if (isTracked) + { + if (trackedScore != null) + throw new InvalidOperationException("Cannot track more than one scores."); + + trackedScore = drawable; + } + drawable.Expanded.BindTo(Expanded); - base.Add(drawable); + Flow.Add(drawable); drawable.TotalScore.BindValueChanged(_ => sorting.Invalidate(), true); - Height = Count * (GameplayLeaderboardScore.PANEL_HEIGHT + Spacing.Y); + int displayCount = Math.Min(Flow.Count, maxPanels); + Height = displayCount * (GameplayLeaderboardScore.PANEL_HEIGHT + Flow.Spacing.Y); + requiresScroll = displayCount != Flow.Count; return drawable; } + public void Clear() + { + Flow.Clear(); + trackedScore = null; + scroll.ScrollToStart(false); + } + protected virtual GameplayLeaderboardScore CreateLeaderboardScoreDrawable(User user, bool isTracked) => new GameplayLeaderboardScore(user, isTracked); - public sealed override void Add(GameplayLeaderboardScore drawable) + protected override void Update() { - throw new NotSupportedException($"Use {nameof(AddPlayer)} instead."); + base.Update(); + + if (requiresScroll && trackedScore != null) + { + float scrollTarget = scroll.GetChildPosInContent(trackedScore) + trackedScore.DrawHeight / 2 - scroll.DrawHeight / 2; + scroll.ScrollTo(scrollTarget, false); + } + + const float panel_height = GameplayLeaderboardScore.PANEL_HEIGHT; + + float fadeBottom = scroll.Current + scroll.DrawHeight; + float fadeTop = scroll.Current + panel_height; + + if (scroll.Current <= 0) fadeTop -= panel_height; + if (!scroll.IsScrolledToEnd()) fadeBottom -= panel_height; + + // logic is mostly shared with Leaderboard, copied here for simplicity. + foreach (var c in Flow.Children) + { + float topY = c.ToSpaceOfOtherDrawable(Vector2.Zero, Flow).Y; + float bottomY = topY + panel_height; + + bool requireTopFade = requiresScroll && topY <= fadeTop; + bool requireBottomFade = requiresScroll && bottomY >= fadeBottom; + + if (!requireTopFade && !requireBottomFade) + c.Colour = Color4.White; + else if (topY > fadeBottom + panel_height || bottomY < fadeTop - panel_height) + c.Colour = Color4.Transparent; + else + { + if (bottomY - fadeBottom > 0 && requiresScroll) + { + c.Colour = ColourInfo.GradientVertical( + Color4.White.Opacity(Math.Min(1 - (topY - fadeBottom) / panel_height, 1)), + Color4.White.Opacity(Math.Min(1 - (bottomY - fadeBottom) / panel_height, 1))); + } + else if (requiresScroll) + { + c.Colour = ColourInfo.GradientVertical( + Color4.White.Opacity(Math.Min(1 - (fadeTop - topY) / panel_height, 1)), + Color4.White.Opacity(Math.Min(1 - (fadeTop - bottomY) / panel_height, 1))); + } + } + } } private void sort() @@ -73,15 +163,26 @@ namespace osu.Game.Screens.Play.HUD if (sorting.IsValid) return; - var orderedByScore = this.OrderByDescending(i => i.TotalScore.Value).ToList(); + var orderedByScore = Flow.OrderByDescending(i => i.TotalScore.Value).ToList(); - for (int i = 0; i < Count; i++) + for (int i = 0; i < Flow.Count; i++) { - SetLayoutPosition(orderedByScore[i], i); + Flow.SetLayoutPosition(orderedByScore[i], i); orderedByScore[i].ScorePosition = i + 1; } sorting.Validate(); } + + private class ManualScrollScrollContainer : OsuScrollContainer + { + public ManualScrollScrollContainer() + { + ScrollbarVisible = false; + } + + public override bool HandlePositionalInput => false; + public override bool HandleNonPositionalInput => false; + } } } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 433bf78e9b..85cf9d1966 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -81,7 +81,10 @@ namespace osu.Game.Screens.Play.HUD [CanBeNull] public User User { get; } - private readonly bool trackedPlayer; + /// + /// Whether this score is the local user or a replay player (and should be focused / always visible). + /// + public readonly bool Tracked; private Container mainFillContainer; @@ -97,11 +100,11 @@ namespace osu.Game.Screens.Play.HUD /// Creates a new . /// /// The score's player. - /// Whether the player is the local user or a replay player. - public GameplayLeaderboardScore([CanBeNull] User user, bool trackedPlayer) + /// Whether the player is the local user or a replay player. + public GameplayLeaderboardScore([CanBeNull] User user, bool tracked) { User = user; - this.trackedPlayer = trackedPlayer; + Tracked = tracked; AutoSizeAxes = Axes.X; Height = PANEL_HEIGHT; @@ -338,7 +341,7 @@ namespace osu.Game.Screens.Play.HUD panelColour = BackgroundColour ?? Color4Extensions.FromHex("7fcc33"); textColour = TextColour ?? Color4.White; } - else if (trackedPlayer) + else if (Tracked) { widthExtension = true; panelColour = BackgroundColour ?? Color4Extensions.FromHex("ffd966"); From e84224f64c057f0d2caac52ad54ac06dc92a77e1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 16:17:27 +0900 Subject: [PATCH 179/961] Rename `AddPlayer` method now that there's no conflict --- osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs | 2 +- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 10257f9027..0441c5641e 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -105,7 +105,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void createLeaderboardScore(BindableDouble score, User user, bool isTracked = false) { - var leaderboardScore = leaderboard.AddPlayer(user, isTracked); + var leaderboardScore = leaderboard.Add(user, isTracked); leaderboardScore.TotalScore.BindTo(score); } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 807289d664..14fcaa91fa 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -75,7 +75,7 @@ namespace osu.Game.Screens.Play.HUD /// Whether the player should be tracked on the leaderboard. /// Set to true for the local player or a player whose replay is currently being played. /// - public ILeaderboardScore AddPlayer([CanBeNull] User user, bool isTracked) + public ILeaderboardScore Add([CanBeNull] User user, bool isTracked) { var drawable = CreateLeaderboardScoreDrawable(user, isTracked); diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 3f9258930e..1c5743a656 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -85,7 +85,7 @@ namespace osu.Game.Screens.Play.HUD var trackedUser = UserScores[user.Id]; - var leaderboardScore = AddPlayer(user, user.Id == api.LocalUser.Value.Id); + var leaderboardScore = Add(user, user.Id == api.LocalUser.Value.Id); leaderboardScore.Accuracy.BindTo(trackedUser.Accuracy); leaderboardScore.TotalScore.BindTo(trackedUser.Score); leaderboardScore.Combo.BindTo(trackedUser.CurrentCombo); From ab1cc6ad4856503da10296681e28b896d9be8a03 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 16:50:09 +0900 Subject: [PATCH 180/961] Fix padding around recent participants icon being uneven --- .../OnlinePlay/Lounge/Components/RecentParticipantsList.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index 7f3fdf01d0..6766a51840 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(4), - Padding = new MarginPadding { Left = 8, Right = 16 }, + Padding = new MarginPadding { Right = 16 }, Children = new Drawable[] { new SpriteIcon @@ -62,6 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Size = new Vector2(16), + Margin = new MarginPadding(8), Icon = FontAwesome.Solid.User, }, avatarFlow = new FillFlowContainer From d07bb10d0294fd4986442cb415b603248d022ed4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 16:52:30 +0900 Subject: [PATCH 181/961] Remove breadcrumbs from header --- osu.Game/Screens/OnlinePlay/Header.cs | 88 +++++---------------------- 1 file changed, 16 insertions(+), 72 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index bf0a53cbb6..c025099ebe 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -2,19 +2,15 @@ // See the LICENCE file in the repository root for full licence text. using Humanizer; +using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { @@ -22,52 +18,29 @@ namespace osu.Game.Screens.OnlinePlay { public const float HEIGHT = 80; + private readonly ScreenStack stack; + private readonly MultiHeaderTitle title; + public Header(string mainTitle, ScreenStack stack) { + this.stack = stack; + RelativeSizeAxes = Axes.X; Height = HEIGHT; + Padding = new MarginPadding { Left = WaveOverlayContainer.WIDTH_PADDING }; - HeaderBreadcrumbControl breadcrumbs; - MultiHeaderTitle title; - - Children = new Drawable[] + Child = title = new MultiHeaderTitle(mainTitle) { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#1f1921"), - }, - new Container - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Left = WaveOverlayContainer.WIDTH_PADDING + OsuScreen.HORIZONTAL_OVERFLOW_PADDING }, - Children = new Drawable[] - { - title = new MultiHeaderTitle(mainTitle) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomLeft, - }, - breadcrumbs = new HeaderBreadcrumbControl(stack) - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft - } - }, - }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.BottomLeft, }; - breadcrumbs.Current.ValueChanged += screen => - { - if (screen.NewValue is IOnlinePlaySubScreen onlineSubScreen) - title.Screen = onlineSubScreen; - }; - - breadcrumbs.Current.TriggerChange(); + stack.ScreenPushed += (_, __) => updateSubScreenTitle(); + stack.ScreenExited += (_, __) => updateSubScreenTitle(); } + private void updateSubScreenTitle() => title.Screen = stack.CurrentScreen as IOnlinePlaySubScreen; + private class MultiHeaderTitle : CompositeDrawable { private const float spacing = 6; @@ -75,9 +48,10 @@ namespace osu.Game.Screens.OnlinePlay private readonly OsuSpriteText dot; private readonly OsuSpriteText pageTitle; + [CanBeNull] public IOnlinePlaySubScreen Screen { - set => pageTitle.Text = value.ShortTitle.Titleize(); + set => pageTitle.Text = value?.ShortTitle.Titleize() ?? string.Empty; } public MultiHeaderTitle(string mainTitle) @@ -125,35 +99,5 @@ namespace osu.Game.Screens.OnlinePlay pageTitle.Colour = dot.Colour = colours.Yellow; } } - - private class HeaderBreadcrumbControl : ScreenBreadcrumbControl - { - public HeaderBreadcrumbControl(ScreenStack stack) - : base(stack) - { - RelativeSizeAxes = Axes.X; - StripColour = Color4.Transparent; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - AccentColour = Color4Extensions.FromHex("#e35c99"); - } - - protected override TabItem CreateTabItem(IScreen value) => new HeaderBreadcrumbTabItem(value) - { - AccentColour = AccentColour - }; - - private class HeaderBreadcrumbTabItem : BreadcrumbTabItem - { - public HeaderBreadcrumbTabItem(IScreen value) - : base(value) - { - Bar.Colour = Color4.Transparent; - } - } - } } } From 3b7aa262d5b559f72511af9c8dfb6230f3c9ba1e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 16:52:35 +0900 Subject: [PATCH 182/961] Make header overlap content --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index fee612c0a5..6238000e85 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -101,7 +101,6 @@ namespace osu.Game.Screens.OnlinePlay new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = Header.HEIGHT }, Children = new[] { header = new Container From b75c20fee421138d8b10b538fe55baf6d59c5d78 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 18:02:00 +0900 Subject: [PATCH 183/961] Adjust positioning and paddings --- osu.Game/Screens/OnlinePlay/Header.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 ++ osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs | 2 ++ osu.Game/Screens/Select/SongSelect.cs | 9 +++++---- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index c025099ebe..58c67a51e8 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay Child = title = new MultiHeaderTitle(mainTitle) { Anchor = Anchor.CentreLeft, - Origin = Anchor.BottomLeft, + Origin = Anchor.CentreLeft, }; stack.ScreenPushed += (_, __) => updateSubScreenTitle(); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index a53e253581..b29a1ab1b6 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -61,6 +61,8 @@ namespace osu.Game.Screens.OnlinePlay.Match protected RoomSubScreen() { + Padding = new MarginPadding { Top = Header.HEIGHT }; + AddRangeInternal(new Drawable[] { BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index be28de5c43..1502463022 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -59,6 +59,8 @@ namespace osu.Game.Screens.OnlinePlay [BackgroundDependencyLoader] private void load() { + LeftArea.Padding = new MarginPadding { Top = Header.HEIGHT }; + initialBeatmap = Beatmap.Value; initialRuleset = Ruleset.Value; initialMods = Mods.Value.ToList(); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 270addc8e6..0e113a71bc 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -79,6 +79,8 @@ namespace osu.Game.Screens.Select protected BeatmapCarousel Carousel { get; private set; } + protected Container LeftArea { get; private set; } + private BeatmapInfoWedge beatmapInfoWedge; private DialogOverlay dialogOverlay; @@ -186,12 +188,12 @@ namespace osu.Game.Screens.Select { new Drawable[] { - new Container + LeftArea = new Container { Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, RelativeSizeAxes = Axes.Both, - + Padding = new MarginPadding { Top = left_area_padding }, Children = new Drawable[] { beatmapInfoWedge = new BeatmapInfoWedge @@ -200,7 +202,6 @@ namespace osu.Game.Screens.Select RelativeSizeAxes = Axes.X, Margin = new MarginPadding { - Top = left_area_padding, Right = left_area_padding, }, }, @@ -210,7 +211,7 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Bottom = Footer.HEIGHT, - Top = WEDGE_HEIGHT + left_area_padding, + Top = WEDGE_HEIGHT, Left = left_area_padding, Right = left_area_padding * 2, }, From b58b5ec2b47af2376b9ff355c5591629af397d55 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Aug 2021 12:14:39 +0300 Subject: [PATCH 184/961] Apply horizontal offset changing once per frame The previous way was causing every-frame invalidation when an overlay is visible. --- osu.Game/OsuGame.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1539d984ae..b6809c0290 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1013,10 +1013,14 @@ namespace osu.Game ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; - ScreenOffsetContainer.X = 0f; + var horizontalOffset = 0f; - if (Settings.IsLoaded) ScreenOffsetContainer.X += (ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X) * SCREEN_OFFSET_RATIO; - if (Notifications.IsLoaded) ScreenOffsetContainer.X += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; + if (Settings.IsLoaded) + horizontalOffset += (ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X) * SCREEN_OFFSET_RATIO; + if (Notifications.IsLoaded) + horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; + + ScreenOffsetContainer.X = horizontalOffset; MenuCursorContainer.CanShowCursor = (ScreenStack.CurrentScreen as IOsuScreen)?.CursorVisible ?? false; } From 8b29f52d9f119a2bfc72b1e6bbb85412f5e54dfb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 12 Aug 2021 16:54:58 +0700 Subject: [PATCH 185/961] update supporter note text Co-authored-by: Dean Herbert --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index c0d78cc887..3d6a469247 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -114,7 +114,7 @@ namespace osu.Game.Overlays.Changelog t.Colour = colour.PinkLighter; }) { - Text = "Not only will you help speed development, but you will also get some extra features and customisations!", + Text = ChangelogStrings.SupportText2.ToString(), Margin = new MarginPadding { Top = 10 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 98859b3759a78649b85b5611c6ff6087e6a64610 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 12 Aug 2021 17:06:11 +0700 Subject: [PATCH 186/961] cache pink colour provider Co-authored-by: Dean Herbert --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 3d6a469247..9bfb141eea 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -25,6 +25,9 @@ namespace osu.Game.Overlays.Changelog private readonly FillFlowContainer textContainer; private readonly Container imageContainer; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); + public ChangelogSupporterPromo() { RelativeSizeAxes = Axes.X; From 18684ad21f52e2821810181a0170f4a98eda66ed Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 12 Aug 2021 17:08:54 +0700 Subject: [PATCH 187/961] remove colour creation in add link --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 9bfb141eea..477745e0ba 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -125,11 +125,7 @@ namespace osu.Game.Overlays.Changelog }; supportLinkText.AddText("Support further development of osu! and "); - supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => - { - t.Colour = colour.PinkDark; - t.Font = t.Font.With(weight: FontWeight.Bold); - }); + supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); supportLinkText.AddText(" today!"); imageContainer.Children = new Drawable[] From ab7bd1df9dade8869369175d53055efcbf40a42d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 19:27:06 +0900 Subject: [PATCH 188/961] Use full-screen background --- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 6238000e85..21e4f047f0 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -21,8 +21,8 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; -using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { @@ -68,9 +68,6 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(CanBeNull = true)] private OsuLogo logo { get; set; } - private Drawable header; - private Drawable headerBackground; - protected OnlinePlayScreen() { Anchor = Anchor.Centre; @@ -101,41 +98,21 @@ namespace osu.Game.Screens.OnlinePlay new Container { RelativeSizeAxes = Axes.Both, - Children = new[] + Children = new Drawable[] { - header = new Container + new HeaderBackgroundSprite { - RelativeSizeAxes = Axes.X, - Height = 400, - Children = new[] - { - headerBackground = new Container - { - RelativeSizeAxes = Axes.Both, - Width = 1.25f, - Masking = true, - Children = new Drawable[] - { - new HeaderBackgroundSprite - { - RelativeSizeAxes = Axes.X, - Height = 400 // Keep a static height so the header doesn't change as it's resized between subscreens - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = -1 }, // 1px padding to avoid a 1px gap due to masking - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(backgroundColour.Opacity(0.5f), backgroundColour) - }, - } - } + RelativeSizeAxes = Axes.Both }, - screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both } + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f)) + }, + screenStack = new OnlinePlaySubScreenStack + { + RelativeSizeAxes = Axes.Both + } } }, new Header(ScreenTitle, screenStack), @@ -288,19 +265,6 @@ namespace osu.Game.Screens.OnlinePlay private void subScreenChanged(IScreen lastScreen, IScreen newScreen) { - switch (newScreen) - { - case LoungeSubScreen _: - header.Delay(OnlinePlaySubScreen.RESUME_TRANSITION_DELAY).ResizeHeightTo(400, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint); - headerBackground.MoveToX(0, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint); - break; - - case RoomSubScreen _: - header.ResizeHeightTo(135, OnlinePlaySubScreen.APPEAR_DURATION, Easing.OutQuint); - headerBackground.MoveToX(-OnlinePlaySubScreen.X_SHIFT, OnlinePlaySubScreen.X_MOVE_DURATION, Easing.OutQuint); - break; - } - if (lastScreen is IOsuScreen lastOsuScreen) Activity.UnbindFrom(lastOsuScreen.Activity); From 512382987e0e85d4fc6825f065fe94677627851a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 17:02:55 +0900 Subject: [PATCH 189/961] Add colour provider for multiplayer usage --- .../Visual/Multiplayer/TestSceneDrawableRoom.cs | 4 ++++ .../Multiplayer/TestSceneRecentParticipantsList.cs | 5 +++++ osu.Game/Overlays/OverlayColourProvider.cs | 7 ++++++- .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 13 ++++++------- .../Lounge/Components/RecentParticipantsList.cs | 5 +++-- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 3 +++ 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index e6a1bbeb92..299bbacf08 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -13,6 +13,7 @@ using osu.Framework.Utils; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; +using osu.Game.Overlays; using osu.Game.Rulesets.Osu; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Beatmaps; @@ -26,6 +27,9 @@ namespace osu.Game.Tests.Visual.Multiplayer [Cached] private readonly Bindable selectedRoom = new Bindable(); + [Cached] + protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + [Test] public void TestMultipleStatuses() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index f05c092dfb..27ccd33440 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -3,9 +3,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Online.Rooms; +using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Users; @@ -17,6 +19,9 @@ namespace osu.Game.Tests.Visual.Multiplayer { private RecentParticipantsList list; + [Cached] + protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + [SetUp] public new void Setup() => Schedule(() => { diff --git a/osu.Game/Overlays/OverlayColourProvider.cs b/osu.Game/Overlays/OverlayColourProvider.cs index 008e7696e1..e7b3e6d873 100644 --- a/osu.Game/Overlays/OverlayColourProvider.cs +++ b/osu.Game/Overlays/OverlayColourProvider.cs @@ -18,6 +18,7 @@ namespace osu.Game.Overlays public static OverlayColourProvider Green { get; } = new OverlayColourProvider(OverlayColourScheme.Green); public static OverlayColourProvider Purple { get; } = new OverlayColourProvider(OverlayColourScheme.Purple); public static OverlayColourProvider Blue { get; } = new OverlayColourProvider(OverlayColourScheme.Blue); + public static OverlayColourProvider Plum { get; } = new OverlayColourProvider(OverlayColourScheme.Plum); public OverlayColourProvider(OverlayColourScheme colourScheme) { @@ -80,6 +81,9 @@ namespace osu.Game.Overlays case OverlayColourScheme.Blue: return 200 / 360f; + + case OverlayColourScheme.Plum: + return 320 / 360f; } } } @@ -92,6 +96,7 @@ namespace osu.Game.Overlays Lime, Green, Purple, - Blue + Blue, + Plum, } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 3a56be64e0..c2a872efe5 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -28,6 +28,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Input.Bindings; using osu.Game.Online.Rooms; +using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Components; using osuTK; using osuTK.Graphics; @@ -41,8 +42,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private const float transition_duration = 60; private const float height = 100; - private static readonly Color4 background_colour = Color4Extensions.FromHex(@"#27302E"); - public event Action StateChanged; protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); @@ -154,7 +153,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } [BackgroundDependencyLoader] - private void load(OsuColour colours, AudioManager audio) + private void load(OverlayColourProvider colours, AudioManager audio) { Children = new Drawable[] { @@ -167,7 +166,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = background_colour, + Colour = colours.Background5, }, new OnlinePlayBackgroundSprite { @@ -208,12 +207,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = background_colour, + Colour = colours.Background5, }, new Box { RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(background_colour, background_colour.Opacity(0.3f)) + Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f)) }, } } @@ -531,7 +530,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private OsuPasswordTextBox passwordTextbox; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { Child = new FillFlowContainer { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index 6766a51840..e22f55a716 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; +using osu.Game.Overlays; using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; @@ -31,7 +32,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } [BackgroundDependencyLoader] - private void load() + private void load(OverlayColourProvider colours) { InternalChildren = new Drawable[] { @@ -44,7 +45,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Child = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"#2E3835") + Colour = colours.Background4, } }, new FillFlowContainer diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index fee612c0a5..86ce61f845 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -29,6 +29,9 @@ namespace osu.Game.Screens.OnlinePlay [Cached] public abstract class OnlinePlayScreen : OsuScreen, IHasSubScreenStack { + [Cached] + protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true; // this is required due to PlayerLoader eventually being pushed to the main stack From 2c07b68f6fca41f997dc32d642fe899e14ca4af1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 17:24:21 +0900 Subject: [PATCH 190/961] Fix incorrect colour for hidden user display --- .../Components/RecentParticipantsList.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index e22f55a716..e6e879d652 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -4,7 +4,6 @@ using System.Collections.Specialized; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -14,7 +13,6 @@ using osu.Game.Overlays; using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { @@ -208,9 +206,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private int count; - private readonly SpriteText countText; + private readonly SpriteText countText = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; - public HiddenUserCount() + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colours) { Size = new Vector2(avatar_size); Alpha = 0; @@ -224,13 +227,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black + Colour = colours.Background5, }, - countText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } + countText } }; } From 127fd4d292d9ac8c95e3f2ec3c6dfb7572e45377 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 17:28:10 +0900 Subject: [PATCH 191/961] Match font weight of design for hidden user count --- .../OnlinePlay/Lounge/Components/RecentParticipantsList.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index e6e879d652..32568f5058 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -8,6 +8,7 @@ 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.Overlays; using osu.Game.Users; @@ -210,6 +211,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Font = OsuFont.Default.With(weight: FontWeight.Bold), }; [BackgroundDependencyLoader] From 8a67304b9fe6a93ac60105ae34ee570fa99b1ea0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 18:10:06 +0900 Subject: [PATCH 192/961] Fix recent participants hidden user logic not handling edge case correctly Hiding just one user never makes sense, so this will now always show up to the required circle count until two users are required to be hidden. This will make the listing more consistent with the width requirement spec. --- .../TestSceneRecentParticipantsList.cs | 46 +++++++++++++----- .../Lounge/Components/DrawableRoom.cs | 4 +- .../Components/RecentParticipantsList.cs | 48 +++++++++++++------ 3 files changed, 71 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index 27ccd33440..2436da4655 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -31,12 +31,36 @@ namespace osu.Game.Tests.Visual.Multiplayer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - NumberOfAvatars = 3 + NumberOfCircles = 3 }; }); [Test] - public void TestAvatarCount() + public void TestCircleCountNearLimit() + { + AddStep("add 8 users", () => + { + for (int i = 0; i < 8; i++) + addUser(i); + }); + AddStep("set 8 circles", () => list.NumberOfCircles = 8); + AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); + + AddStep("add one more user", () => addUser(9)); + AddAssert("2 hidden users", () => list.ChildrenOfType().Single().Count == 2); + + AddStep("remove first user", () => removeUserAt(0)); + AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); + + AddStep("add one more user", () => addUser(9)); + AddAssert("2 hidden users", () => list.ChildrenOfType().Single().Count == 2); + + AddStep("remove last user", () => removeUserAt(8)); + AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); + } + + [Test] + public void TestCircleCount() { AddStep("add 50 users", () => { @@ -44,12 +68,12 @@ namespace osu.Game.Tests.Visual.Multiplayer addUser(i); }); - AddStep("set 3 avatars", () => list.NumberOfAvatars = 3); - AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddStep("set 3 circles", () => list.NumberOfCircles = 3); + AddAssert("3 circles displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("47 hidden users", () => list.ChildrenOfType().Single().Count == 47); - AddStep("set 10 avatars", () => list.NumberOfAvatars = 10); - AddAssert("10 avatars displayed", () => list.ChildrenOfType().Count() == 10); + AddStep("set 10 circles", () => list.NumberOfCircles = 10); + AddAssert("10 circles displayed", () => list.ChildrenOfType().Count() == 10); AddAssert("40 hidden users", () => list.ChildrenOfType().Single().Count == 40); } @@ -63,24 +87,24 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddStep("remove from start", () => removeUserAt(0)); - AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("3 circles displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("46 hidden users", () => list.ChildrenOfType().Single().Count == 46); AddStep("remove from end", () => removeUserAt(SelectedRoom.Value.RecentParticipants.Count - 1)); - AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("3 circles displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("45 hidden users", () => list.ChildrenOfType().Single().Count == 45); AddRepeatStep("remove 45 users", () => removeUserAt(0), 45); - AddAssert("3 avatars displayed", () => list.ChildrenOfType().Count() == 3); + AddAssert("3 circles displayed", () => list.ChildrenOfType().Count() == 3); AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); AddAssert("hidden users bubble hidden", () => list.ChildrenOfType().Single().Alpha < 0.5f); AddStep("remove another user", () => removeUserAt(0)); - AddAssert("2 avatars displayed", () => list.ChildrenOfType().Count() == 2); + AddAssert("2 circles displayed", () => list.ChildrenOfType().Count() == 2); AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); AddRepeatStep("remove the remaining two users", () => removeUserAt(0), 2); - AddAssert("0 avatars displayed", () => !list.ChildrenOfType().Any()); + AddAssert("0 circles displayed", () => !list.ChildrenOfType().Any()); } private void addUser(int id) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index c2a872efe5..193fb0cf57 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -120,7 +120,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components numberOfAvatars = value; if (recentParticipantsList != null) - recentParticipantsList.NumberOfAvatars = value; + recentParticipantsList.NumberOfCircles = value; } } @@ -315,7 +315,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - NumberOfAvatars = NumberOfAvatars + NumberOfCircles = NumberOfAvatars } } }, diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index 32568f5058..ab13f27469 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Specialized; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -21,6 +22,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { private const float avatar_size = 36; + private bool canDisplayMoreUsers = true; + private FillFlowContainer avatarFlow; private HiddenUserCount hiddenUsers; @@ -91,14 +94,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components ParticipantCount.BindValueChanged(_ => updateHiddenUserCount(), true); } - private int numberOfAvatars = 3; + private int numberOfCircles = 3; - public int NumberOfAvatars + /// + /// The maximum number of circles visible (including the "hidden count" circle in the overflow case). + /// + public int NumberOfCircles { - get => numberOfAvatars; + get => numberOfCircles; set { - numberOfAvatars = value; + numberOfCircles = value; if (LoadState < LoadState.Loaded) return; @@ -107,6 +113,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components clearUsers(); foreach (var u in RecentParticipants) addUser(u); + + updateHiddenUserCount(); } } @@ -136,34 +144,46 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components addUser(u); break; } + + updateHiddenUserCount(); } private void addUser(User user) { - if (avatarFlow.Count < NumberOfAvatars) - avatarFlow.Add(new CircularAvatar { User = user }); + if (!canDisplayMoreUsers) + return; - updateHiddenUserCount(); + if (avatarFlow.Count < NumberOfCircles) + avatarFlow.Add(new CircularAvatar { User = user }); + else if (avatarFlow.Count == NumberOfCircles) + avatarFlow.Remove(avatarFlow.Last()); } private void removeUser(User user) { - if (avatarFlow.RemoveAll(a => a.User == user) > 0) - { - if (RecentParticipants.Count >= NumberOfAvatars) - avatarFlow.Add(new CircularAvatar { User = RecentParticipants.First(u => avatarFlow.All(a => a.User != u)) }); - } + var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u)); + if (nextUser == null) + return; - updateHiddenUserCount(); + if (canDisplayMoreUsers || NumberOfCircles == RecentParticipants.Count) + avatarFlow.Add(new CircularAvatar { User = nextUser }); } private void clearUsers() { + canDisplayMoreUsers = true; avatarFlow.Clear(); updateHiddenUserCount(); } - private void updateHiddenUserCount() => hiddenUsers.Count = ParticipantCount.Value - avatarFlow.Count; + private void updateHiddenUserCount() + { + int count = ParticipantCount.Value - avatarFlow.Count; + + Debug.Assert(count != 1); + + hiddenUsers.Count = count; + } private class CircularAvatar : CompositeDrawable { From 7b66616dc40df3f9f87ac0afe67d46915d4c2711 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 18:47:22 +0900 Subject: [PATCH 193/961] Simplify logic and test/fix edge case --- .../TestSceneRecentParticipantsList.cs | 36 ++++++++--- .../Components/RecentParticipantsList.cs | 60 ++++++++++--------- 2 files changed, 62 insertions(+), 34 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index 2436da4655..7d3880dd16 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - NumberOfCircles = 3 + NumberOfCircles = 4 }; }); @@ -43,6 +43,7 @@ namespace osu.Game.Tests.Visual.Multiplayer for (int i = 0; i < 8; i++) addUser(i); }); + AddStep("set 8 circles", () => list.NumberOfCircles = 8); AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); @@ -59,6 +60,27 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("0 hidden users", () => list.ChildrenOfType().Single().Count == 0); } + [Test] + public void TestHiddenUsersBecomeDisplayed() + { + AddStep("add 8 users", () => + { + for (int i = 0; i < 8; i++) + addUser(i); + }); + + AddStep("set 3 circles", () => list.NumberOfCircles = 3); + + for (int i = 0; i < 8; i++) + { + AddStep("remove user", () => removeUserAt(0)); + int remainingUsers = 7 - i; + + int displayedUsers = remainingUsers > 3 ? 2 : remainingUsers; + AddAssert($"{displayedUsers} avatars displayed", () => list.ChildrenOfType().Count() == displayedUsers); + } + } + [Test] public void TestCircleCount() { @@ -69,12 +91,12 @@ namespace osu.Game.Tests.Visual.Multiplayer }); AddStep("set 3 circles", () => list.NumberOfCircles = 3); - AddAssert("3 circles displayed", () => list.ChildrenOfType().Count() == 3); - AddAssert("47 hidden users", () => list.ChildrenOfType().Single().Count == 47); + AddAssert("2 users displayed", () => list.ChildrenOfType().Count() == 2); + AddAssert("48 hidden users", () => list.ChildrenOfType().Single().Count == 48); AddStep("set 10 circles", () => list.NumberOfCircles = 10); - AddAssert("10 circles displayed", () => list.ChildrenOfType().Count() == 10); - AddAssert("40 hidden users", () => list.ChildrenOfType().Single().Count == 40); + AddAssert("9 users displayed", () => list.ChildrenOfType().Count() == 9); + AddAssert("41 hidden users", () => list.ChildrenOfType().Single().Count == 41); } [Test] @@ -109,18 +131,18 @@ namespace osu.Game.Tests.Visual.Multiplayer private void addUser(int id) { - SelectedRoom.Value.ParticipantCount.Value++; SelectedRoom.Value.RecentParticipants.Add(new User { Id = id, Username = $"User {id}" }); + SelectedRoom.Value.ParticipantCount.Value++; } private void removeUserAt(int index) { - SelectedRoom.Value.ParticipantCount.Value--; SelectedRoom.Value.RecentParticipants.RemoveAt(index); + SelectedRoom.Value.ParticipantCount.Value--; } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index ab13f27469..3085286ccb 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -22,8 +22,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { private const float avatar_size = 36; - private bool canDisplayMoreUsers = true; - private FillFlowContainer avatarFlow; private HiddenUserCount hiddenUsers; @@ -91,10 +89,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components base.LoadComplete(); RecentParticipants.BindCollectionChanged(onParticipantsChanged, true); - ParticipantCount.BindValueChanged(_ => updateHiddenUserCount(), true); + ParticipantCount.BindValueChanged(_ => updateHiddenUsers(), true); } - private int numberOfCircles = 3; + private int numberOfCircles = 4; /// /// The maximum number of circles visible (including the "hidden count" circle in the overflow case). @@ -114,7 +112,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components foreach (var u in RecentParticipants) addUser(u); - updateHiddenUserCount(); + updateHiddenUsers(); } } @@ -145,44 +143,43 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components break; } - updateHiddenUserCount(); + updateHiddenUsers(); } + private int displayedCircles => avatarFlow.Count + (hiddenUsers.Count > 0 ? 1 : 0); + private void addUser(User user) { - if (!canDisplayMoreUsers) - return; - - if (avatarFlow.Count < NumberOfCircles) + if (displayedCircles < NumberOfCircles) avatarFlow.Add(new CircularAvatar { User = user }); - else if (avatarFlow.Count == NumberOfCircles) - avatarFlow.Remove(avatarFlow.Last()); } private void removeUser(User user) { - var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u)); - if (nextUser == null) - return; - - if (canDisplayMoreUsers || NumberOfCircles == RecentParticipants.Count) - avatarFlow.Add(new CircularAvatar { User = nextUser }); + avatarFlow.RemoveAll(a => a.User == user); } private void clearUsers() { - canDisplayMoreUsers = true; avatarFlow.Clear(); - updateHiddenUserCount(); + updateHiddenUsers(); } - private void updateHiddenUserCount() + private void updateHiddenUsers() { - int count = ParticipantCount.Value - avatarFlow.Count; + int hiddenCount = 0; + if (RecentParticipants.Count > NumberOfCircles) + hiddenCount = ParticipantCount.Value - NumberOfCircles + 1; - Debug.Assert(count != 1); + hiddenUsers.Count = hiddenCount; - hiddenUsers.Count = count; + if (displayedCircles > NumberOfCircles) + avatarFlow.Remove(avatarFlow.Last()); + else if (displayedCircles < NumberOfCircles) + { + var nextUser = RecentParticipants.FirstOrDefault(u => avatarFlow.All(a => a.User != u)); + if (nextUser != null) addUser(nextUser); + } } private class CircularAvatar : CompositeDrawable @@ -193,9 +190,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components set => avatar.User = value; } - private readonly UpdateableAvatar avatar; + private readonly UpdateableAvatar avatar = new UpdateableAvatar(showUsernameTooltip: true) { RelativeSizeAxes = Axes.Both }; - public CircularAvatar() + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colours) { Size = new Vector2(avatar_size); @@ -203,7 +201,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { RelativeSizeAxes = Axes.Both, Masking = true, - Child = avatar = new UpdateableAvatar(showUsernameTooltip: true) { RelativeSizeAxes = Axes.Both } + Children = new Drawable[] + { + new Box + { + Colour = colours.Background5, + RelativeSizeAxes = Axes.Both, + }, + avatar + } }; } } From 10195e0c53574a8036b691541357a2595fa878fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 18:51:50 +0900 Subject: [PATCH 194/961] Add total user count --- .../Components/RecentParticipantsList.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs index 3085286ccb..bc658f45e4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RecentParticipantsList.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Specialized; -using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -23,7 +22,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private const float avatar_size = 36; private FillFlowContainer avatarFlow; + private HiddenUserCount hiddenUsers; + private OsuSpriteText totalCount; public RecentParticipantsList() { @@ -63,16 +64,23 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Size = new Vector2(16), - Margin = new MarginPadding(8), + Margin = new MarginPadding { Left = 8 }, Icon = FontAwesome.Solid.User, }, + totalCount = new OsuSpriteText + { + Font = OsuFont.Default.With(weight: FontWeight.Bold), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, avatarFlow = new FillFlowContainer { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(4) + Spacing = new Vector2(4), + Margin = new MarginPadding { Left = 4 }, }, hiddenUsers = new HiddenUserCount { @@ -89,7 +97,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components base.LoadComplete(); RecentParticipants.BindCollectionChanged(onParticipantsChanged, true); - ParticipantCount.BindValueChanged(_ => updateHiddenUsers(), true); + ParticipantCount.BindValueChanged(_ => + { + updateHiddenUsers(); + totalCount.Text = ParticipantCount.Value.ToString(); + }, true); } private int numberOfCircles = 4; From e89aea1fc2b91265ee518b450b9fb3ca02b781c0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 12 Aug 2021 19:38:53 +0900 Subject: [PATCH 195/961] Add some padding between scroll bar and content --- .../Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index b9b034272d..5e5863c7c4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -50,6 +50,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + // account for the fact we are in a scroll container and want a bit of spacing from the scroll bar. + Padding = new MarginPadding { Right = 5 }; + InternalChild = new OsuContextMenuContainer { RelativeSizeAxes = Axes.X, From 047b37788bb8087c248986de83a4b4732d362020 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 19:48:15 +0900 Subject: [PATCH 196/961] Merge online play filter control with the lounge subscreen --- .../TestScenePlaylistsFilterControl.cs | 23 ---- .../Lounge/Components/FilterControl.cs | 125 ----------------- .../Components/PlaylistsFilterControl.cs | 57 -------- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 129 ++++++++++++++---- .../Multiplayer/MultiplayerFilterControl.cs | 17 --- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 7 +- .../Playlists/PlaylistsLoungeSubScreen.cs | 44 +++++- 7 files changed, 154 insertions(+), 248 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs deleted file mode 100644 index 40e191dd7e..0000000000 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsFilterControl.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Game.Screens.OnlinePlay.Lounge.Components; - -namespace osu.Game.Tests.Visual.Playlists -{ - public class TestScenePlaylistsFilterControl : OsuTestScene - { - public TestScenePlaylistsFilterControl() - { - Child = new PlaylistsFilterControl - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - RelativeSizeAxes = Axes.X, - Width = 0.7f, - Height = 80, - }; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs deleted file mode 100644 index e2f02fca68..0000000000 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/FilterControl.cs +++ /dev/null @@ -1,125 +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.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Threading; -using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; -using osu.Game.Rulesets; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Lounge.Components -{ - public abstract class FilterControl : CompositeDrawable - { - protected readonly FillFlowContainer Filters; - - [Resolved(CanBeNull = true)] - private Bindable filter { get; set; } - - [Resolved] - private IBindable ruleset { get; set; } - - private readonly SearchTextBox search; - private readonly Dropdown statusDropdown; - - protected FilterControl() - { - RelativeSizeAxes = Axes.X; - Height = 70; - - InternalChild = new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(10), - Children = new Drawable[] - { - search = new FilterSearchTextBox - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.X, - Width = 0.6f, - }, - Filters = new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - Child = statusDropdown = new SlimEnumDropdown - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.None, - Width = 160, - } - }, - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - filter ??= new Bindable(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - search.Current.BindValueChanged(_ => updateFilterDebounced()); - ruleset.BindValueChanged(_ => UpdateFilter()); - statusDropdown.Current.BindValueChanged(_ => UpdateFilter(), true); - } - - private ScheduledDelegate scheduledFilterUpdate; - - private void updateFilterDebounced() - { - scheduledFilterUpdate?.Cancel(); - scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200); - } - - protected void UpdateFilter() => Scheduler.AddOnce(updateFilter); - - private void updateFilter() - { - scheduledFilterUpdate?.Cancel(); - - var criteria = CreateCriteria(); - criteria.SearchString = search.Current.Value; - criteria.Status = statusDropdown.Current.Value; - criteria.Ruleset = ruleset.Value; - - filter.Value = criteria; - } - - protected virtual FilterCriteria CreateCriteria() => new FilterCriteria(); - - public bool HoldFocus - { - get => search.HoldFocus; - set => search.HoldFocus = value; - } - - public void TakeFocus() => search.TakeFocus(); - - private class FilterSearchTextBox : SearchTextBox - { - [BackgroundDependencyLoader] - private void load() - { - BackgroundUnfocused = OsuColour.Gray(0.06f); - BackgroundFocused = OsuColour.Gray(0.12f); - } - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs deleted file mode 100644 index bbf34d3893..0000000000 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/PlaylistsFilterControl.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.UserInterface; - -namespace osu.Game.Screens.OnlinePlay.Lounge.Components -{ - public class PlaylistsFilterControl : FilterControl - { - private readonly Dropdown categoryDropdown; - - public PlaylistsFilterControl() - { - Filters.Add(categoryDropdown = new SlimEnumDropdown - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - RelativeSizeAxes = Axes.None, - Width = 160, - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - categoryDropdown.Current.BindValueChanged(_ => UpdateFilter()); - } - - protected override FilterCriteria CreateCriteria() - { - var criteria = base.CreateCriteria(); - - switch (categoryDropdown.Current.Value) - { - case PlaylistsCategory.Normal: - criteria.Category = "normal"; - break; - - case PlaylistsCategory.Spotlight: - criteria.Category = "spotlight"; - break; - } - - return criteria; - } - - private enum PlaylistsCategory - { - Any, - Normal, - Spotlight - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 122b30b1d2..1c28405e40 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Allocation; @@ -9,24 +10,28 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Screens; +using osu.Framework.Threading; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Overlays; +using osu.Game.Rulesets; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge { [Cached] public abstract class LoungeSubScreen : OnlinePlaySubScreen { + private const float button_height = 25; + public override string Title => "Lounge"; protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -41,7 +46,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private readonly IBindable initialRoomsReceived = new Bindable(); private readonly IBindable operationInProgress = new Bindable(); - private FilterControl filter; private LoadingLayer loadingLayer; [Resolved] @@ -53,31 +57,33 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [Resolved(CanBeNull = true)] private OngoingOperationTracker ongoingOperationTracker { get; set; } + [Resolved(CanBeNull = true)] + private Bindable filter { get; set; } + + [Resolved] + private IBindable ruleset { get; set; } + [CanBeNull] private IDisposable joiningRoomOperation { get; set; } private RoomsContainer roomsContainer; + private SearchTextBox searchTextBox; + private Dropdown statusDropdown; [BackgroundDependencyLoader] private void load() { + filter ??= new Bindable(new FilterCriteria()); + OsuScrollContainer scrollContainer; InternalChildren = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.X, - Height = 100, - Colour = Color4.Black, - Alpha = 0.5f, - }, new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Top = 20, Left = WaveOverlayContainer.WIDTH_PADDING, Right = WaveOverlayContainer.WIDTH_PADDING, }, @@ -86,26 +92,48 @@ namespace osu.Game.Screens.OnlinePlay.Lounge RelativeSizeAxes = Axes.Both, RowDimensions = new[] { - new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, Header.HEIGHT), + new Dimension(GridSizeMode.Absolute, button_height), new Dimension(GridSizeMode.Absolute, 20) }, Content = new[] { + new Drawable[] + { + searchTextBox = new LoungeSearchTextBox + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.X, + Width = 0.6f, + }, + }, new Drawable[] { new Container { - RelativeSizeAxes = Axes.X, - Height = 70, - Depth = -1, + RelativeSizeAxes = Axes.Both, + Depth = float.MinValue, // Contained filters should appear over the top of rooms. Children = new Drawable[] { - filter = CreateFilterControl(), Buttons.WithChild(CreateNewRoomButton().With(d => { - d.Size = new Vector2(150, 25); + d.Size = new Vector2(150, button_height); d.Action = () => Open(); - })) + })), + new FillFlowContainer + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d => + { + d.Anchor = Anchor.TopRight; + d.Origin = Anchor.TopRight; + })) + } } } }, @@ -145,6 +173,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { base.LoadComplete(); + searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced()); + ruleset.BindValueChanged(_ => UpdateFilter()); + initialRoomsReceived.BindTo(RoomManager.InitialRoomsReceived); initialRoomsReceived.BindValueChanged(_ => updateLoadingLayer()); @@ -153,13 +184,50 @@ namespace osu.Game.Screens.OnlinePlay.Lounge operationInProgress.BindTo(ongoingOperationTracker.InProgress); operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true); } + + updateFilter(); } - protected override void OnFocus(FocusEvent e) + #region Filtering + + protected void UpdateFilter() => Scheduler.AddOnce(updateFilter); + + private ScheduledDelegate scheduledFilterUpdate; + + private void updateFilterDebounced() { - filter.TakeFocus(); + scheduledFilterUpdate?.Cancel(); + scheduledFilterUpdate = Scheduler.AddDelayed(UpdateFilter, 200); } + private void updateFilter() + { + scheduledFilterUpdate?.Cancel(); + filter.Value = CreateFilterCriteria(); + } + + protected virtual FilterCriteria CreateFilterCriteria() => new FilterCriteria + { + SearchString = searchTextBox.Current.Value, + Ruleset = ruleset.Value, + Status = statusDropdown.Current.Value + }; + + protected virtual IEnumerable CreateFilterControls() + { + statusDropdown = new SlimEnumDropdown + { + RelativeSizeAxes = Axes.None, + Width = 160, + }; + + statusDropdown.Current.BindValueChanged(_ => UpdateFilter()); + + yield return statusDropdown; + } + + #endregion + public override void OnEntering(IScreen last) { base.OnEntering(last); @@ -191,14 +259,19 @@ namespace osu.Game.Screens.OnlinePlay.Lounge base.OnSuspending(next); } + protected override void OnFocus(FocusEvent e) + { + searchTextBox.TakeFocus(); + } + private void onReturning() { - filter.HoldFocus = true; + searchTextBox.HoldFocus = true; } private void onLeaving() { - filter.HoldFocus = false; + searchTextBox.HoldFocus = false; // ensure any password prompt is dismissed. this.HidePopover(); @@ -243,8 +316,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge this.Push(CreateRoomSubScreen(room)); } - protected abstract FilterControl CreateFilterControl(); - protected abstract OsuButton CreateNewRoomButton(); /// @@ -262,5 +333,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge else loadingLayer.Hide(); } + + private class LoungeSearchTextBox : SearchTextBox + { + [BackgroundDependencyLoader] + private void load() + { + BackgroundUnfocused = OsuColour.Gray(0.06f); + BackgroundFocused = OsuColour.Gray(0.12f); + } + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs deleted file mode 100644 index 37e0fd109a..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerFilterControl.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Game.Screens.OnlinePlay.Lounge.Components; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer -{ - public class MultiplayerFilterControl : FilterControl - { - protected override FilterCriteria CreateCriteria() - { - var criteria = base.CreateCriteria(); - criteria.Category = "realtime"; - return criteria; - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 621ff8881f..a7eaa37faa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -21,7 +21,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } - protected override FilterControl CreateFilterControl() => new MultiplayerFilterControl(); + protected override FilterCriteria CreateFilterCriteria() + { + var criteria = base.CreateFilterCriteria(); + criteria.Category = "realtime"; + return criteria; + } protected override OsuButton CreateNewRoomButton() => new CreateMultiplayerMatchButton(); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index 4db1d6380d..254769d06b 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -1,7 +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.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Rooms; @@ -16,7 +20,38 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved] private IAPIProvider api { get; set; } - protected override FilterControl CreateFilterControl() => new PlaylistsFilterControl(); + private Dropdown categoryDropdown; + + protected override IEnumerable CreateFilterControls() + { + categoryDropdown = new SlimEnumDropdown + { + RelativeSizeAxes = Axes.None, + Width = 160, + }; + + categoryDropdown.Current.BindValueChanged(_ => UpdateFilter()); + + return base.CreateFilterControls().Append(categoryDropdown); + } + + protected override FilterCriteria CreateFilterCriteria() + { + var criteria = base.CreateFilterCriteria(); + + switch (categoryDropdown.Current.Value) + { + case PlaylistsCategory.Normal: + criteria.Category = "normal"; + break; + + case PlaylistsCategory.Spotlight: + criteria.Category = "spotlight"; + break; + } + + return criteria; + } protected override OsuButton CreateNewRoomButton() => new CreatePlaylistsRoomButton(); @@ -30,5 +65,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room); + + private enum PlaylistsCategory + { + Any, + Normal, + Spotlight + } } } From 050f2d6b0d379a675c2d5dbee3d7ba80e85873f5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 19:51:03 +0900 Subject: [PATCH 197/961] Add background to room subscreen --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index b29a1ab1b6..0074479a4d 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -8,8 +8,10 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; using osu.Game.Audio; using osu.Game.Beatmaps; @@ -65,6 +67,11 @@ namespace osu.Game.Screens.OnlinePlay.Match AddRangeInternal(new Drawable[] { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. + }, BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker { SelectedItem = { BindTarget = SelectedItem } From 03351cf434d100356e1d16fdc86e07d05541a374 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 20:01:53 +0900 Subject: [PATCH 198/961] Add blur to background --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 21e4f047f0..d1c701974e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -22,6 +22,7 @@ using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Users; +using osuTK; using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay @@ -100,9 +101,14 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new HeaderBackgroundSprite + new BufferedContainer { - RelativeSizeAxes = Axes.Both + RelativeSizeAxes = Axes.Both, + BlurSigma = new Vector2(10), + Child = new HeaderBackgroundSprite + { + RelativeSizeAxes = Axes.Both + } }, new Box { From 83703e42835630d5d600f529efd900df38785c15 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 12 Aug 2021 20:08:14 +0900 Subject: [PATCH 199/961] Add colour provider to online play dependencies --- .../Visual/Multiplayer/TestSceneRecentParticipantsList.cs | 5 ----- .../Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs index 7d3880dd16..50ec2bf3ac 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRecentParticipantsList.cs @@ -3,11 +3,9 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Online.Rooms; -using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Visual.OnlinePlay; using osu.Game.Users; @@ -19,9 +17,6 @@ namespace osu.Game.Tests.Visual.Multiplayer { private RecentParticipantsList list; - [Cached] - protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); - [SetUp] public new void Setup() => Schedule(() => { diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs index ddbbfe501b..05ba509a73 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs @@ -7,6 +7,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.Rooms; +using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay; using osu.Game.Screens.OnlinePlay.Lounge.Components; @@ -46,6 +47,7 @@ namespace osu.Game.Tests.Visual.OnlinePlay CacheAs(Filter); CacheAs(OngoingOperationTracker); CacheAs(AvailabilityTracker); + CacheAs(new OverlayColourProvider(OverlayColourScheme.Plum)); } public object Get(Type type) From 3d7866e82da57bc422af3bb0cc22557653d10964 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Aug 2021 14:14:54 +0300 Subject: [PATCH 200/961] Calculate horizontal offset on present overlays only --- osu.Game/OsuGame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b6809c0290..b8a4388282 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1015,9 +1015,9 @@ namespace osu.Game var horizontalOffset = 0f; - if (Settings.IsLoaded) + if (Settings.IsLoaded && Settings.IsPresent) horizontalOffset += (ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X) * SCREEN_OFFSET_RATIO; - if (Notifications.IsLoaded) + if (Notifications.IsLoaded && Notifications.IsPresent) horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; ScreenOffsetContainer.X = horizontalOffset; From bb1d74255e70081a806f9f3a9db773b6a3b06262 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Aug 2021 14:15:51 +0300 Subject: [PATCH 201/961] Remove unrequired parenthesis --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b8a4388282..f92f7e9e8c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1016,7 +1016,7 @@ namespace osu.Game var horizontalOffset = 0f; if (Settings.IsLoaded && Settings.IsPresent) - horizontalOffset += (ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X) * SCREEN_OFFSET_RATIO; + horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SCREEN_OFFSET_RATIO; if (Notifications.IsLoaded && Notifications.IsPresent) horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; From 40db228e910c90b87e719ff08da9f12e7219a5a5 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 12 Aug 2021 19:34:44 +0700 Subject: [PATCH 202/961] change to osu text flow container --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 477745e0ba..bdbba20f5c 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -111,7 +111,7 @@ namespace osu.Game.Overlays.Changelog RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, }, - new TextFlowContainer(t => + new OsuTextFlowContainer(t => { t.Font = t.Font.With(size: 12); t.Colour = colour.PinkLighter; From 66ba24e86540146fcab7ecba094e3d6d67c34da1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Thu, 12 Aug 2021 20:36:47 +0700 Subject: [PATCH 203/961] create local link flow container --- .../Changelog/ChangelogSupporterPromo.cs | 46 ++++++++++++++++--- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index bdbba20f5c..f617b4fc82 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.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 osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -12,6 +14,7 @@ using osu.Framework.Graphics.Textures; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -25,9 +28,6 @@ namespace osu.Game.Overlays.Changelog private readonly FillFlowContainer textContainer; private readonly Container imageContainer; - [Cached] - private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Pink); - public ChangelogSupporterPromo() { RelativeSizeAxes = Axes.X; @@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Changelog [BackgroundDependencyLoader] private void load(OsuColour colour, TextureStore textures) { - LinkFlowContainer supportLinkText; + SupporterPromoLinkFlowContainer supportLinkText; textContainer.Children = new Drawable[] { new OsuSpriteText @@ -102,7 +102,7 @@ namespace osu.Game.Overlays.Changelog Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), Margin = new MarginPadding { Bottom = 20 }, }, - supportLinkText = new LinkFlowContainer(t => + supportLinkText = new SupporterPromoLinkFlowContainer(t => { t.Font = t.Font.With(size: 14); t.Colour = colour.PinkLighter; @@ -125,7 +125,7 @@ namespace osu.Game.Overlays.Changelog }; supportLinkText.AddText("Support further development of osu! and "); - supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); + supportLinkText.AddLink("become and osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); supportLinkText.AddText(" today!"); imageContainer.Children = new Drawable[] @@ -149,5 +149,39 @@ namespace osu.Game.Overlays.Changelog }, }; } + + private class SupporterPromoLinkFlowContainer : LinkFlowContainer + { + public SupporterPromoLinkFlowContainer(Action defaultCreationParameters) + : base(defaultCreationParameters) + { + } + + public new void AddLink(string text, string url, Action creationParameters) => + AddInternal(new SupporterPromoLinkCompiler(AddText(text, creationParameters)) { Url = url }); + + private class SupporterPromoLinkCompiler : DrawableLinkCompiler + { + [Resolved(CanBeNull = true)] + private OsuGame game { get; set; } + + public string Url; + + public SupporterPromoLinkCompiler(IEnumerable parts) + : base(parts) + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + TooltipText = Url; + Action = () => game?.HandleLink(Url); + IdleColour = colour.PinkDark; + HoverColour = Color4.White; + } + } + } } } From 1069f9d50119bfc08e97cb28bc33a7608e568587 Mon Sep 17 00:00:00 2001 From: TheOmyNomy Date: Fri, 13 Aug 2021 00:13:03 +1000 Subject: [PATCH 204/961] Always add cursor trail for legacy cursor with disjoint trail --- .../Skinning/Legacy/LegacyCursorTrail.cs | 24 ++++++++--- .../UI/Cursor/CursorTrail.cs | 43 ++++++++++++------- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index f6fd3e36ab..f98d936b48 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -5,10 +5,12 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Shaders; using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.UI.Cursor; using osu.Game.Skinning; +using osuTK; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { @@ -21,14 +23,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private double lastTrailTime; private IBindable cursorSize; + private Vector2? currentPosition; + public LegacyCursorTrail(ISkin skin) { this.skin = skin; } [BackgroundDependencyLoader] - private void load(OsuConfigManager config) + private void load(ShaderManager shaders, OsuConfigManager config) { + Shader = shaders.Load(@"LegacyCursorTrail", FragmentShaderDescriptor.TEXTURE); + Texture = skin.GetTexture("cursortrail"); disjointTrail = skin.GetTexture("cursormiddle") == null; @@ -59,18 +65,24 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override float IntervalMultiplier => 1 / Math.Max(cursorSize.Value, 1); - protected override bool OnMouseMove(MouseMoveEvent e) + protected override void Update() { - if (!disjointTrail) - return base.OnMouseMove(e); + base.Update(); + + if (!disjointTrail || !currentPosition.HasValue) + return; if (Time.Current - lastTrailTime >= disjoint_trail_time_separation) { lastTrailTime = Time.Current; - return base.OnMouseMove(e); + AddTrail(currentPosition.Value); } + } - return false; + protected override bool OnMouseMove(MouseMoveEvent e) + { + currentPosition = e.ScreenSpaceMousePosition; + return base.OnMouseMove(e); } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 7f86e9daf7..66a9302f5f 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -28,7 +28,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly TrailPart[] parts = new TrailPart[max_sprites]; private int currentIndex; - private IShader shader; + + protected IShader Shader; + private double timeOffset; private float time; @@ -63,7 +65,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor [BackgroundDependencyLoader] private void load(ShaderManager shaders) { - shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); + Shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); } protected override void LoadComplete() @@ -141,21 +143,32 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override bool OnMouseMove(MouseMoveEvent e) { - Vector2 pos = e.ScreenSpaceMousePosition; + Vector2 position = e.ScreenSpaceMousePosition; if (lastPosition == null) { - lastPosition = pos; + lastPosition = position; resampler.AddPosition(lastPosition.Value); return base.OnMouseMove(e); } - foreach (Vector2 pos2 in resampler.AddPosition(pos)) - { - Trace.Assert(lastPosition.HasValue); + if (InterpolateMovements) + AddTrail(position); - if (InterpolateMovements) + return base.OnMouseMove(e); + } + + protected void AddTrail(Vector2 position) + { + if (!lastPosition.HasValue) + return; + + if (InterpolateMovements) + { + foreach (Vector2 pos2 in resampler.AddPosition(position)) { + Trace.Assert(lastPosition.HasValue); + // ReSharper disable once PossibleInvalidOperationException Vector2 pos1 = lastPosition.Value; Vector2 diff = pos2 - pos1; @@ -170,14 +183,12 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor addPart(lastPosition.Value); } } - else - { - lastPosition = pos2; - addPart(lastPosition.Value); - } } - - return base.OnMouseMove(e); + else + { + lastPosition = position; + addPart(lastPosition.Value); + } } private void addPart(Vector2 screenSpacePosition) @@ -223,7 +234,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { base.ApplyState(); - shader = Source.shader; + shader = Source.Shader; texture = Source.texture; size = Source.partSize; time = Source.time; From 5f67d991b4a02ad983cda08c4fc673618c6fc93e Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 12 Aug 2021 19:17:32 +0200 Subject: [PATCH 205/961] Localise beatmap info. --- osu.Game/Overlays/BeatmapSet/MetadataSection.cs | 3 ++- osu.Game/Overlays/BeatmapSet/MetadataType.cs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs index 3648c55714..f1b9f98528 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataSection.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataSection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -46,7 +47,7 @@ namespace osu.Game.Overlays.BeatmapSet AutoSizeAxes = Axes.Y, Child = new OsuSpriteText { - Text = this.type.ToString(), + Text = this.type.GetLocalisableDescription(), Font = OsuFont.GetFont(weight: FontWeight.Bold, size: 14), }, }, diff --git a/osu.Game/Overlays/BeatmapSet/MetadataType.cs b/osu.Game/Overlays/BeatmapSet/MetadataType.cs index 1ab4c6887e..f992dca0ef 100644 --- a/osu.Game/Overlays/BeatmapSet/MetadataType.cs +++ b/osu.Game/Overlays/BeatmapSet/MetadataType.cs @@ -1,14 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; + namespace osu.Game.Overlays.BeatmapSet { public enum MetadataType { + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoTags))] Tags, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoSource))] Source, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoDescription))] Description, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoGenre))] Genre, + + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowInfoLanguage))] Language } } From 4b4c1448eadd3837117ac2814ffd89f145e804cc Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 12 Aug 2021 19:19:03 +0200 Subject: [PATCH 206/961] Localise success rate metrics. --- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index 3bb36545cd..d370e57f14 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -4,10 +4,12 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osu.Game.Screens.Select.Details; namespace osu.Game.Overlays.BeatmapSet @@ -42,7 +44,7 @@ namespace osu.Game.Overlays.BeatmapSet int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0; var rate = playCount != 0 ? (float)passCount / playCount : 0; - successPercent.Text = rate.ToString("0.#%"); + successPercent.Text = rate.ToLocalisableString("0.#%"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); @@ -64,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = "Success Rate", + Text = BeatmapsetsStrings.ShowInfoSuccessRate, Font = OsuFont.GetFont(size: 12) }, successRate = new Bar @@ -89,7 +91,7 @@ namespace osu.Game.Overlays.BeatmapSet { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Text = "Points of Failure", + Text = BeatmapsetsStrings.ShowInfoPointsOfFailure, Font = OsuFont.GetFont(size: 12), Margin = new MarginPadding { Vertical = 20 }, }, From 4d26bb67142d47283ea9ed7a223eaad2ccfd0957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 19:27:32 +0200 Subject: [PATCH 207/961] Scale score panel to remove overlap with team score display --- .../OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 0e4655e336..8b7aaa02e7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -15,6 +14,7 @@ using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play.HUD; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -36,6 +36,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { + ScorePanelList.Anchor = ScorePanelList.Origin = Anchor.TopCentre; + ScorePanelList.Scale = new Vector2(0.9f); + ScorePanelList.Y = 75; + if (teamScores.Count == 2) { var redScore = teamScores.First().Value; From 828268ad4dfd50a83d7a919de8c29b9df7887047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 19:32:23 +0200 Subject: [PATCH 208/961] Add winner text background to increase contrast --- .../Multiplayer/MultiplayerResultsScreen.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 8b7aaa02e7..92b20f4915 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -6,7 +6,10 @@ 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.Effects; +using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; @@ -22,6 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { private readonly SortedDictionary teamScores; + private Container winnerBackground; private Drawable winnerText; public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, SortedDictionary teamScores) @@ -36,6 +40,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { + const float winner_background_half_height = 250; + ScorePanelList.Anchor = ScorePanelList.Origin = Anchor.TopCentre; ScorePanelList.Scale = new Vector2(0.9f); ScorePanelList.Y = 75; @@ -59,6 +65,32 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Team1Score = { BindTarget = redScore }, Team2Score = { BindTarget = blueScore }, }, + winnerBackground = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.X, + Height = winner_background_half_height, + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0), Colour4.Black.Opacity(0.4f)) + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = winner_background_half_height, + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0.4f), Colour4.Black.Opacity(0)) + } + } + }, (winnerText = new OsuSpriteText { Alpha = 0, @@ -83,7 +115,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer using (BeginDelayedSequence(300)) { - winnerText.FadeInFromZero(600, Easing.InQuint); + const double fade_in_duration = 600; + + winnerText.FadeInFromZero(fade_in_duration, Easing.InQuint); + winnerBackground.FadeInFromZero(fade_in_duration, Easing.InQuint); winnerText .ScaleTo(10) @@ -91,6 +126,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer .Then() .ScaleTo(1.02f, 1600, Easing.OutQuint) .FadeOut(5000, Easing.InQuad); + winnerBackground.Delay(2200).FadeOut(2000); } } } From d08d22e3e943c5e411dfe5198cc09f1f06691306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 19:48:57 +0200 Subject: [PATCH 209/961] Ensure tests wait for screen load --- .../Multiplayer/TestSceneMultiplayerTeamResults.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index 2b04955d5e..94043c311a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -18,6 +18,8 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestDisplayWithTeams() { + MultiplayerResultsScreen screen = null; + AddStep("show results screen", () => { var rulesetInfo = new OsuRuleset().RulesetInfo; @@ -48,13 +50,17 @@ namespace osu.Game.Tests.Visual.Multiplayer { 1, new BindableInt(1048576) } }; - Stack.Push(new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); }); + + AddUntilStep("wait for loaded", () => screen.IsLoaded); } [Test] public void TestDisplayWithoutTeams() { + MultiplayerResultsScreen screen = null; + AddStep("show results screen", () => { var rulesetInfo = new OsuRuleset().RulesetInfo; @@ -81,8 +87,10 @@ namespace osu.Game.Tests.Visual.Multiplayer SortedDictionary teamScores = new SortedDictionary(); - Stack.Push(new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); }); + + AddUntilStep("wait for loaded", () => screen.IsLoaded); } } } From f06f13215b731a39d9128a30d52d3449fd3277ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 20:01:31 +0200 Subject: [PATCH 210/961] Split off multiplayer team results screen to separate class The previous version tried to keep both normal multiplayer and team multiplayer results as one screen, but didn't check that team-specific components aren't null in `LoadComplete()`. To decrease number of conditional, split off the team results screen to a separate implementation, and choose one or the other at push time in `MultiplayerPlayer`, depending on team count. --- .../TestSceneMultiplayerTeamResults.cs | 6 +- .../Multiplayer/MultiplayerPlayer.cs | 4 +- .../Multiplayer/MultiplayerResultsScreen.cs | 118 +--------------- .../MultiplayerTeamResultsScreen.cs | 133 ++++++++++++++++++ 4 files changed, 139 insertions(+), 122 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index 94043c311a..8878cbdfcb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { 1, new BindableInt(1048576) } }; - Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + Stack.Push(screen = new MultiplayerTeamResultsScreen(score, 1, playlistItem, teamScores)); }); AddUntilStep("wait for loaded", () => screen.IsLoaded); @@ -85,9 +85,7 @@ namespace osu.Game.Tests.Visual.Multiplayer BeatmapID = beatmapInfo.ID, }; - SortedDictionary teamScores = new SortedDictionary(); - - Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem, teamScores)); + Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem)); }); AddUntilStep("wait for loaded", () => screen.IsLoaded); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 3c892d03df..ca1a3710ab 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -181,7 +181,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override ResultsScreen CreateResults(ScoreInfo score) { Debug.Assert(RoomId.Value != null); - return new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem, leaderboard.TeamScores); + return leaderboard.TeamScores.Count == 2 + ? new MultiplayerTeamResultsScreen(score, RoomId.Value.Value, PlaylistItem, leaderboard.TeamScores) + : new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs index 92b20f4915..140b3c45d8 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerResultsScreen.cs @@ -1,133 +1,17 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -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.Effects; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Localisation; using osu.Game.Online.Rooms; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Playlists; -using osu.Game.Screens.Play.HUD; -using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerResultsScreen : PlaylistsResultsScreen { - private readonly SortedDictionary teamScores; - - private Container winnerBackground; - private Drawable winnerText; - - public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, SortedDictionary teamScores) + public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem) : base(score, roomId, playlistItem, false, false) { - this.teamScores = teamScores; - } - - [Resolved] - private OsuColour colours { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - const float winner_background_half_height = 250; - - ScorePanelList.Anchor = ScorePanelList.Origin = Anchor.TopCentre; - ScorePanelList.Scale = new Vector2(0.9f); - ScorePanelList.Y = 75; - - if (teamScores.Count == 2) - { - var redScore = teamScores.First().Value; - var blueScore = teamScores.Last().Value; - - // eventually this will be replaced by team names coming from the multiplayer match state. - string winner = redScore.Value > blueScore.Value ? @"Red" : @"Blue"; - - var winnerColour = redScore.Value > blueScore.Value ? colours.TeamColourRed : colours.TeamColourBlue; - - AddRangeInternal(new Drawable[] - { - new MatchScoreDisplay - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Team1Score = { BindTarget = redScore }, - Team2Score = { BindTarget = blueScore }, - }, - winnerBackground = new Container - { - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Alpha = 0, - Children = new[] - { - new Box - { - RelativeSizeAxes = Axes.X, - Height = winner_background_half_height, - Anchor = Anchor.Centre, - Origin = Anchor.BottomCentre, - Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0), Colour4.Black.Opacity(0.4f)) - }, - new Box - { - RelativeSizeAxes = Axes.X, - Height = winner_background_half_height, - Anchor = Anchor.Centre, - Origin = Anchor.TopCentre, - Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0.4f), Colour4.Black.Opacity(0)) - } - } - }, - (winnerText = new OsuSpriteText - { - Alpha = 0, - Font = OsuFont.Torus.With(size: 80, weight: FontWeight.Bold), - Text = MultiplayerResultsScreenStrings.TeamWins(winner), - Blending = BlendingParameters.Additive - }).WithEffect(new GlowEffect - { - Colour = winnerColour, - }).With(e => - { - e.Anchor = Anchor.Centre; - e.Origin = Anchor.Centre; - }) - }); - } - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - using (BeginDelayedSequence(300)) - { - const double fade_in_duration = 600; - - winnerText.FadeInFromZero(fade_in_duration, Easing.InQuint); - winnerBackground.FadeInFromZero(fade_in_duration, Easing.InQuint); - - winnerText - .ScaleTo(10) - .ScaleTo(1, 600, Easing.InQuad) - .Then() - .ScaleTo(1.02f, 1600, Easing.OutQuint) - .FadeOut(5000, Easing.InQuad); - winnerBackground.Delay(2200).FadeOut(2000); - } } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs new file mode 100644 index 0000000000..fc5b72e210 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs @@ -0,0 +1,133 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Localisation; +using osu.Game.Online.Rooms; +using osu.Game.Scoring; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer +{ + public class MultiplayerTeamResultsScreen : MultiplayerResultsScreen + { + private readonly SortedDictionary teamScores; + + private Container winnerBackground; + private Drawable winnerText; + + public MultiplayerTeamResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, SortedDictionary teamScores) + : base(score, roomId, playlistItem) + { + if (teamScores.Count != 2) + throw new NotSupportedException(@"This screen currently only supports 2 teams"); + + this.teamScores = teamScores; + } + + [Resolved] + private OsuColour colours { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + const float winner_background_half_height = 250; + + ScorePanelList.Anchor = ScorePanelList.Origin = Anchor.TopCentre; + ScorePanelList.Scale = new Vector2(0.9f); + ScorePanelList.Y = 75; + + var redScore = teamScores.First().Value; + var blueScore = teamScores.Last().Value; + + // eventually this will be replaced by team names coming from the multiplayer match state. + string winner = redScore.Value > blueScore.Value ? @"Red" : @"Blue"; + + var winnerColour = redScore.Value > blueScore.Value ? colours.TeamColourRed : colours.TeamColourBlue; + + AddRangeInternal(new Drawable[] + { + new MatchScoreDisplay + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Team1Score = { BindTarget = redScore }, + Team2Score = { BindTarget = blueScore }, + }, + winnerBackground = new Container + { + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Alpha = 0, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.X, + Height = winner_background_half_height, + Anchor = Anchor.Centre, + Origin = Anchor.BottomCentre, + Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0), Colour4.Black.Opacity(0.4f)) + }, + new Box + { + RelativeSizeAxes = Axes.X, + Height = winner_background_half_height, + Anchor = Anchor.Centre, + Origin = Anchor.TopCentre, + Colour = ColourInfo.GradientVertical(Colour4.Black.Opacity(0.4f), Colour4.Black.Opacity(0)) + } + } + }, + (winnerText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.Torus.With(size: 80, weight: FontWeight.Bold), + Text = MultiplayerResultsScreenStrings.TeamWins(winner), + Blending = BlendingParameters.Additive + }).WithEffect(new GlowEffect + { + Colour = winnerColour, + }).With(e => + { + e.Anchor = Anchor.Centre; + e.Origin = Anchor.Centre; + }) + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + using (BeginDelayedSequence(300)) + { + const double fade_in_duration = 600; + + winnerText.FadeInFromZero(fade_in_duration, Easing.InQuint); + winnerBackground.FadeInFromZero(fade_in_duration, Easing.InQuint); + + winnerText + .ScaleTo(10) + .ScaleTo(1, 600, Easing.InQuad) + .Then() + .ScaleTo(1.02f, 1600, Easing.OutQuint) + .FadeOut(5000, Easing.InQuad); + winnerBackground.Delay(2200).FadeOut(2000); + } + } + } +} From d9190607e43dfea970ea56e97d3b151c4cb9321a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 20:21:53 +0200 Subject: [PATCH 211/961] Add test coverage for both teams winning --- .../Multiplayer/TestSceneMultiplayerTeamResults.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index 8878cbdfcb..d6a2988685 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -15,8 +15,9 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneMultiplayerTeamResults : ScreenTestScene { - [Test] - public void TestDisplayWithTeams() + [TestCase(7483253, 1048576)] + [TestCase(1048576, 7483253)] + public void TestDisplayWithTeams(int team1Score, int team2Score) { MultiplayerResultsScreen screen = null; @@ -46,8 +47,8 @@ namespace osu.Game.Tests.Visual.Multiplayer SortedDictionary teamScores = new SortedDictionary { - { 0, new BindableInt(7483253) }, - { 1, new BindableInt(1048576) } + { 0, new BindableInt(team1Score) }, + { 1, new BindableInt(team2Score) } }; Stack.Push(screen = new MultiplayerTeamResultsScreen(score, 1, playlistItem, teamScores)); From 53b4cdfb0269f5861c725fc33e8fc467ebe707e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 20:38:24 +0200 Subject: [PATCH 212/961] Handle ties in team vs. results screen --- .../TestSceneMultiplayerTeamResults.cs | 1 + ...=> MultiplayerTeamResultsScreenStrings.cs} | 9 +++++-- .../MultiplayerTeamResultsScreen.cs | 27 ++++++++++++++++--- 3 files changed, 31 insertions(+), 6 deletions(-) rename osu.Game/Localisation/{MultiplayerResultsScreenStrings.cs => MultiplayerTeamResultsScreenStrings.cs} (64%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index d6a2988685..a21996383f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -17,6 +17,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { [TestCase(7483253, 1048576)] [TestCase(1048576, 7483253)] + [TestCase(1048576, 1048576)] public void TestDisplayWithTeams(int team1Score, int team2Score) { MultiplayerResultsScreen screen = null; diff --git a/osu.Game/Localisation/MultiplayerResultsScreenStrings.cs b/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs similarity index 64% rename from osu.Game/Localisation/MultiplayerResultsScreenStrings.cs rename to osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs index e586faba66..111c068bbd 100644 --- a/osu.Game/Localisation/MultiplayerResultsScreenStrings.cs +++ b/osu.Game/Localisation/MultiplayerTeamResultsScreenStrings.cs @@ -5,15 +5,20 @@ using osu.Framework.Localisation; namespace osu.Game.Localisation { - public static class MultiplayerResultsScreenStrings + public static class MultiplayerTeamResultsScreenStrings { - private const string prefix = @"osu.Game.Resources.Localisation.MultiplayerResultsScreen"; + private const string prefix = @"osu.Game.Resources.Localisation.MultiplayerTeamResultsScreen"; /// /// "Team {0} wins!" /// public static LocalisableString TeamWins(string winner) => new TranslatableString(getKey(@"team_wins"), @"Team {0} wins!", winner); + /// + /// "The teams are tied!" + /// + public static LocalisableString TheTeamsAreTied => new TranslatableString(getKey(@"the_teams_are_tied"), @"The teams are tied!"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } \ No newline at end of file diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs index fc5b72e210..e98898b9da 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Localisation; @@ -52,10 +53,28 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer var redScore = teamScores.First().Value; var blueScore = teamScores.Last().Value; - // eventually this will be replaced by team names coming from the multiplayer match state. - string winner = redScore.Value > blueScore.Value ? @"Red" : @"Blue"; + LocalisableString winner; + Colour4 winnerColour; - var winnerColour = redScore.Value > blueScore.Value ? colours.TeamColourRed : colours.TeamColourBlue; + int comparison = redScore.Value.CompareTo(blueScore.Value); + + if (comparison < 0) + { + // team name should eventually be coming from the multiplayer match state. + winner = MultiplayerTeamResultsScreenStrings.TeamWins(@"Blue"); + winnerColour = colours.TeamColourBlue; + } + else if (comparison > 0) + { + // team name should eventually be coming from the multiplayer match state. + winner = MultiplayerTeamResultsScreenStrings.TeamWins(@"Red"); + winnerColour = colours.TeamColourRed; + } + else + { + winner = MultiplayerTeamResultsScreenStrings.TheTeamsAreTied; + winnerColour = Colour4.White.Opacity(0.5f); + } AddRangeInternal(new Drawable[] { @@ -96,7 +115,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { Alpha = 0, Font = OsuFont.Torus.With(size: 80, weight: FontWeight.Bold), - Text = MultiplayerResultsScreenStrings.TeamWins(winner), + Text = winner, Blending = BlendingParameters.Additive }).WithEffect(new GlowEffect { From 68f454b51a8ecc9753e21e323be29a9067b6b406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 21:09:08 +0200 Subject: [PATCH 213/961] Enable NRT in explosion-related classes and streamline null handling --- .../Skinning/Default/DefaultHitExplosion.cs | 3 --- .../Skinning/Legacy/LegacyHitExplosion.cs | 3 --- osu.Game.Rulesets.Catch/UI/HitExplosion.cs | 14 +++++++------- osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs | 2 ++ osu.Game.Rulesets.Catch/UI/IHitExplosion.cs | 2 ++ 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs index 680fbc7b15..e1fad564a3 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Default/DefaultHitExplosion.cs @@ -72,9 +72,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Default public void Animate(HitExplosionEntry entry) { - if (entry == null) - return; - X = entry.Position; Scale = new Vector2(entry.HitObject.Scale); setColour(entry.ObjectColour); diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 78b0e1e327..08f86df2f3 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -62,9 +62,6 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy public void Animate(HitExplosionEntry entry) { - if (entry == null) - return; - Colour = entry.ObjectColour; using (BeginAbsoluteSequence(entry.LifetimeStart)) diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs index 35af39348d..955b1e6edb 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosion.cs @@ -1,28 +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 osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Skinning.Default; using osu.Game.Rulesets.Objects.Pooling; using osu.Game.Skinning; +#nullable enable + namespace osu.Game.Rulesets.Catch.UI { public class HitExplosion : PoolableDrawableWithLifetime { - private SkinnableDrawable skinnableExplosion; + private readonly SkinnableDrawable skinnableExplosion; public HitExplosion() { RelativeSizeAxes = Axes.Both; Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; - } - [BackgroundDependencyLoader] - private void load() - { InternalChild = skinnableExplosion = new SkinnableDrawable(new CatchSkinComponent(CatchSkinComponents.HitExplosion), _ => new DefaultHitExplosion()) { CentreComponent = false, @@ -44,8 +41,11 @@ namespace osu.Game.Rulesets.Catch.UI apply(Entry); } - private void apply(HitExplosionEntry entry) + private void apply(HitExplosionEntry? entry) { + if (entry == null) + return; + ApplyTransformsAt(double.MinValue, true); ClearTransforms(true); diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs index 749a448314..815a0d8c98 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs @@ -6,6 +6,8 @@ using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Judgements; using osuTK.Graphics; +#nullable enable + namespace osu.Game.Rulesets.Catch.UI { public class HitExplosionEntry : LifetimeEntry diff --git a/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs b/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs index 4a9d7e8ac0..c744c00d9a 100644 --- a/osu.Game.Rulesets.Catch/UI/IHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/UI/IHitExplosion.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. +#nullable enable + namespace osu.Game.Rulesets.Catch.UI { /// From f3045b315285c1d82ce144c635055e47236df4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 21:13:45 +0200 Subject: [PATCH 214/961] Add comment about swapped sprite names --- osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index 08f86df2f3..c2570c4d1f 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -56,6 +56,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy { var defaultLegacySkin = skins.DefaultLegacySkin; + // sprite names intentionally swapped to match stable member naming / ease of cross-referencing explosion1.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-2"); explosion2.Texture = defaultLegacySkin.GetTexture("scoreboard-explosion-1"); } From e79150d4da09d35870380e2d92156ec9b011728e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 21:14:46 +0200 Subject: [PATCH 215/961] Reorder constructor arguments for `HitExplosionEntry` --- osu.Game.Rulesets.Catch/UI/Catcher.cs | 2 +- osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index aec8e752a7..5cd85aac56 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -367,7 +367,7 @@ namespace osu.Game.Rulesets.Catch.UI } private void addLighting(JudgementResult judgementResult, Color4 colour, float x) => - hitExplosionContainer.Add(new HitExplosionEntry(judgementResult, colour, x, Time.Current)); + hitExplosionContainer.Add(new HitExplosionEntry(Time.Current, judgementResult, colour, x)); private CaughtObject getCaughtObject(PalpableCatchHitObject source) { diff --git a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs index 815a0d8c98..88871c77f6 100644 --- a/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs +++ b/osu.Game.Rulesets.Catch/UI/HitExplosionEntry.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.UI /// public float Position { get; } - public HitExplosionEntry(JudgementResult judgementResult, Color4 objectColour, float position, double startTime) + public HitExplosionEntry(double startTime, JudgementResult judgementResult, Color4 objectColour, float position) { LifetimeStart = startTime; Position = position; From b84f2381065a00021c88361714387bf715441d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 12 Aug 2021 22:33:09 +0200 Subject: [PATCH 216/961] Adjust scaling numbers to be closer to stable --- osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs index c2570c4d1f..c262b0a4ac 100644 --- a/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs +++ b/osu.Game.Rulesets.Catch/Skinning/Legacy/LegacyHitExplosion.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; RelativeSizeAxes = Axes.Both; - Scale = new Vector2(0.4f); + Scale = new Vector2(0.5f); InternalChildren = new[] { @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Catch.Skinning.Legacy explosion1.Position = new Vector2(explosionOffset, 0); explosion1.FadeOutFromOne(300); - explosion1.ScaleTo(new Vector2(20 * scale, 1.1f), 160, Easing.Out); + explosion1.ScaleTo(new Vector2(16 * scale, 1.1f), 160, Easing.Out); } explosion2.Scale = new Vector2(0.9f, 1); From 7aa361d77280c14ea53d7a563a59d988a7b7f29c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 09:02:13 +0900 Subject: [PATCH 217/961] Remove now-incorrect test --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 7ff0368fc2..7f961d4c8b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -405,8 +405,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden); - testLeave("lounge tab item", () => this.ChildrenOfType.BreadcrumbTabItem>().First().TriggerClick()); - testLeave("back button", () => multiplayerScreen.OnBackButton()); // mimics home button and OS window close From 524102951348592f84312bb946e1eb85b40298c7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 10:27:26 +0900 Subject: [PATCH 218/961] Use new FadeExponent shader uniform --- .../Skinning/Legacy/LegacyCursorTrail.cs | 6 ++---- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 17 +++++++++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index f98d936b48..9493dc2ef1 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -5,7 +5,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Shaders; using osu.Framework.Input.Events; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.UI.Cursor; @@ -31,10 +30,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } [BackgroundDependencyLoader] - private void load(ShaderManager shaders, OsuConfigManager config) + private void load(OsuConfigManager config) { - Shader = shaders.Load(@"LegacyCursorTrail", FragmentShaderDescriptor.TEXTURE); - Texture = skin.GetTexture("cursortrail"); disjointTrail = skin.GetTexture("cursormiddle") == null; @@ -60,6 +57,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } protected override double FadeDuration => disjointTrail ? 150 : 500; + protected override float FadeExponent => 1; protected override bool InterpolateMovements => !disjointTrail; diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 66a9302f5f..b05bf5c93e 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -26,11 +26,14 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { private const int max_sprites = 2048; + /// + /// An exponentiating factor to ease the trail fade. + /// + protected virtual float FadeExponent => 1.7f; + private readonly TrailPart[] parts = new TrailPart[max_sprites]; private int currentIndex; - - protected IShader Shader; - + private IShader shader; private double timeOffset; private float time; @@ -65,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor [BackgroundDependencyLoader] private void load(ShaderManager shaders) { - Shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); + shader = shaders.Load(@"CursorTrail", FragmentShaderDescriptor.TEXTURE); } protected override void LoadComplete() @@ -217,10 +220,10 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private Texture texture; private float time; + private float fadeExponent; private readonly TrailPart[] parts = new TrailPart[max_sprites]; private Vector2 size; - private Vector2 originPosition; private readonly QuadBatch vertexBatch = new QuadBatch(max_sprites, 1); @@ -234,10 +237,11 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor { base.ApplyState(); - shader = Source.Shader; + shader = Source.shader; texture = Source.texture; size = Source.partSize; time = Source.time; + fadeExponent = Source.FadeExponent; originPosition = Vector2.Zero; @@ -260,6 +264,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor shader.Bind(); shader.GetUniform("g_FadeClock").UpdateValue(ref time); + shader.GetUniform("g_FadeExponent").UpdateValue(ref fadeExponent); texture.TextureGL.Bind(); From 7cc0a2a76fdb8acecf4502bac1a75279c9b29e49 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 12:10:33 +0900 Subject: [PATCH 219/961] Refactor to fix InterpolateMovements=false --- .../Skinning/Legacy/LegacyCursorTrail.cs | 7 +++++- .../UI/Cursor/CursorTrail.cs | 24 +++++++------------ 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index 9493dc2ef1..587ff4b573 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -79,8 +79,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override bool OnMouseMove(MouseMoveEvent e) { + if (!disjointTrail) + return base.OnMouseMove(e); + currentPosition = e.ScreenSpaceMousePosition; - return base.OnMouseMove(e); + + // Intentionally block the base call as we're adding the trails ourselves. + return false; } } } diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index b05bf5c93e..7a95111c91 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -146,33 +146,25 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override bool OnMouseMove(MouseMoveEvent e) { - Vector2 position = e.ScreenSpaceMousePosition; - - if (lastPosition == null) - { - lastPosition = position; - resampler.AddPosition(lastPosition.Value); - return base.OnMouseMove(e); - } - - if (InterpolateMovements) - AddTrail(position); - + AddTrail(e.ScreenSpaceMousePosition); return base.OnMouseMove(e); } protected void AddTrail(Vector2 position) { - if (!lastPosition.HasValue) - return; - if (InterpolateMovements) { + if (!lastPosition.HasValue) + { + lastPosition = position; + resampler.AddPosition(lastPosition.Value); + return; + } + foreach (Vector2 pos2 in resampler.AddPosition(position)) { Trace.Assert(lastPosition.HasValue); - // ReSharper disable once PossibleInvalidOperationException Vector2 pos1 = lastPosition.Value; Vector2 diff = pos2 - pos1; float distance = diff.Length; From 2b86416cb268e717633b8f6d65d9772bb1ea022b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 06:27:57 +0300 Subject: [PATCH 220/961] Hide player settings overlay on multi-spectator player loader --- .../Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs | 7 +++++++ osu.Game/Screens/Play/PlayerLoader.cs | 7 ++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs index 5a1d28e9c4..52e4a6e012 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs @@ -3,6 +3,7 @@ using System; using JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Screens.Play; @@ -19,6 +20,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { } + [BackgroundDependencyLoader] + private void load() + { + PlayerSettingsGroups.Alpha = 0f; + } + protected override void LogoArriving(OsuLogo logo, bool resuming) { } diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 5f6b4ca2b0..1f8387ac67 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -48,6 +48,11 @@ namespace osu.Game.Screens.Play protected BeatmapMetadataDisplay MetadataInfo; + /// + /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. + /// + protected FillFlowContainer PlayerSettingsGroups; + protected VisualSettings VisualSettings; protected Task LoadTask { get; private set; } @@ -140,7 +145,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - new FillFlowContainer + PlayerSettingsGroups = new FillFlowContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, From c10320f23914fd8f15ff0c5ee30ca943a5de8519 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 06:28:07 +0300 Subject: [PATCH 221/961] Hide and disable player settings overlay on multi-spectator player --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 4 ++++ osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 8 ++++++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 2c157b0564..71defa2e07 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Scoring; @@ -34,6 +35,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate private void load() { spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); + + HUDOverlay.PlayerSettingsOverlay.State.Value = Visibility.Hidden; + HUDOverlay.PlayerSettingsOverlay.State.Disabled = true; } protected override void UpdateAfterChildren() diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index ffcbb06fb3..efd37194d3 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Play.HUD if (e.ControlPressed) { - if (e.Key == Key.H && ReplayLoaded) + if (e.Key == Key.H && ReplayLoaded && !State.Disabled) { ToggleVisibility(); return true; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 2cf2555b3e..919886cae7 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -240,13 +240,17 @@ namespace osu.Game.Screens.Play if (e.NewValue) { - PlayerSettingsOverlay.Show(); + if (!PlayerSettingsOverlay.State.Disabled) + PlayerSettingsOverlay.Show(); + ModDisplay.FadeIn(200); KeyCounter.Margin = new MarginPadding(10) { Bottom = 30 }; } else { - PlayerSettingsOverlay.Hide(); + if (!PlayerSettingsOverlay.State.Disabled) + PlayerSettingsOverlay.Hide(); + ModDisplay.Delay(2000).FadeOut(200); KeyCounter.Margin = new MarginPadding(10); } From 1892db7f37e0d916826fef0d4788da4d78ce2531 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 06:31:39 +0300 Subject: [PATCH 222/961] Add test coverage --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 65b1d6d53a..ad60582ace 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -6,6 +6,7 @@ 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.Online.Multiplayer; @@ -13,6 +14,8 @@ using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Rulesets.UI; using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate; using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; +using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Users; @@ -80,6 +83,19 @@ namespace osu.Game.Tests.Visual.Multiplayer AddWaitStep("wait a bit", 20); } + [Test] + public void TestSpectatorPlayerSettingsHidden() + { + start(new[] { PLAYER_1_ID, PLAYER_2_ID }); + loadSpectateScreen(false); + + AddUntilStep("wait for player loaders", () => this.ChildrenOfType().Count() == 2); + AddAssert("all player loader settings hidden", () => this.ChildrenOfType().All(l => l.ChildrenOfType>().Single().Alpha == 0f)); + + AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded); + AddAssert("all player settings hidden", () => this.ChildrenOfType().All(p => p.ChildrenOfType().Single().State.Value == Visibility.Hidden)); + } + [Test] public void TestTeamDisplay() { From e913c8f92fdff9cd6f76c5b63cd079e15b8bbc8a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 13:07:02 +0900 Subject: [PATCH 223/961] Change strings to verbatim --- .../OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index a7eaa37faa..ad7882abc2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override FilterCriteria CreateFilterCriteria() { var criteria = base.CreateFilterCriteria(); - criteria.Category = "realtime"; + criteria.Category = @"realtime"; return criteria; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index 254769d06b..eee4d4f407 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -42,11 +42,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists switch (categoryDropdown.Current.Value) { case PlaylistsCategory.Normal: - criteria.Category = "normal"; + criteria.Category = @"normal"; break; case PlaylistsCategory.Spotlight: - criteria.Category = "spotlight"; + criteria.Category = @"spotlight"; break; } From cbeecff347b350458f4858ab97722f39c875bccf Mon Sep 17 00:00:00 2001 From: LiangXiang Shen Date: Fri, 13 Aug 2021 12:17:38 +0800 Subject: [PATCH 224/961] Apply suggestions from code review Co-authored-by: Joseph Madamba --- osu.Game/Localisation/GraphicsSettingsStrings.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Localisation/GraphicsSettingsStrings.cs b/osu.Game/Localisation/GraphicsSettingsStrings.cs index 989eaf19b9..0e384f983f 100644 --- a/osu.Game/Localisation/GraphicsSettingsStrings.cs +++ b/osu.Game/Localisation/GraphicsSettingsStrings.cs @@ -55,14 +55,14 @@ namespace osu.Game.Localisation public static LocalisableString Resolution => new TranslatableString(getKey(@"resolution"), @"Resolution"); /// - /// "UI Scaling" + /// "UI scaling" /// - public static LocalisableString UIScaling => new TranslatableString(getKey(@"ui_scaling"), @"UI Scaling"); + public static LocalisableString UIScaling => new TranslatableString(getKey(@"ui_scaling"), @"UI scaling"); /// - /// "Screen Scaling" + /// "Screen scaling" /// - public static LocalisableString ScreenScaling => new TranslatableString(getKey(@"screen_scaling"), @"Screen Scaling"); + public static LocalisableString ScreenScaling => new TranslatableString(getKey(@"screen_scaling"), @"Screen scaling"); /// /// "Horizontal position" @@ -95,14 +95,14 @@ namespace osu.Game.Localisation public static LocalisableString DetailSettingsHeader => new TranslatableString(getKey(@"detail_settings_header"), @"Detail Settings"); /// - /// "Storyboard / Video" + /// "Storyboard / video" /// - public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / Video"); + public static LocalisableString StoryboardVideo => new TranslatableString(getKey(@"storyboard_video"), @"Storyboard / video"); /// - /// "Hit Lighting" + /// "Hit lighting" /// - public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit Lighting"); + public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit lighting"); /// /// "Screenshot format" From e93660c0f4f0936828548479711d2c3031514128 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 13:19:34 +0900 Subject: [PATCH 225/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 454bb46059..33d3a623ed 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e6219fcb85..6ccd34dd48 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 9904946363..b6623da540 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 2850f6ce95d9f9f258a68dce0874e75cdcc17ab2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 13:24:05 +0900 Subject: [PATCH 226/961] Privatise counter again --- .../Visual/Online/TestSceneOfflineCommentsContainer.cs | 4 +++- osu.Game/Overlays/Comments/CommentsContainer.cs | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index af0d06dce3..628ae0971b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics; @@ -12,6 +13,7 @@ using osu.Framework.Allocation; using osu.Game.Online.API.Requests.Responses; using osu.Game.Users; using JetBrains.Annotations; +using osu.Framework.Testing; namespace osu.Game.Tests.Visual.Online { @@ -186,7 +188,7 @@ namespace osu.Game.Tests.Visual.Online public void ShowComments(CommentBundle bundle) { - CommentCounter.Current.Value = 0; + this.ChildrenOfType().Single().Current.Value = 0; ClearComments(); OnSuccess(bundle); } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index ee24c4086b..fe8d6f0178 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Comments private FillFlowContainer content; private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; - protected TotalCommentsCounter CommentCounter; + private TotalCommentsCounter commentCounter; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Comments Direction = FillDirection.Vertical, Children = new Drawable[] { - CommentCounter = new TotalCommentsCounter(), + commentCounter = new TotalCommentsCounter(), new CommentsHeader { Sort = { BindTarget = Sort }, @@ -143,7 +143,7 @@ namespace osu.Game.Overlays.Comments return; // only reset when changing ID/type. other refetch ops are generally just changing sort order. - CommentCounter.Current.Value = 0; + commentCounter.Current.Value = 0; refetchComments(); } @@ -181,7 +181,7 @@ namespace osu.Game.Overlays.Comments protected void OnSuccess(CommentBundle response) { - CommentCounter.Current.Value = response.Total; + commentCounter.Current.Value = response.Total; if (!response.Comments.Any()) { From 8dc7a925e7e4a05de0f288fa9bee5dc684169f54 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 07:28:57 +0300 Subject: [PATCH 227/961] Expire instead of hiding and disabling visibility state Since it's a temporary change until the spectator interface gets improved, no need to add further logic. --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 4 +--- .../Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs | 2 +- osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs | 2 +- osu.Game/Screens/Play/HUDOverlay.cs | 8 ++------ 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 71defa2e07..b0ea361dbb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -4,7 +4,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics.Containers; using osu.Framework.Timing; using osu.Game.Beatmaps; using osu.Game.Scoring; @@ -36,8 +35,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); - HUDOverlay.PlayerSettingsOverlay.State.Value = Visibility.Hidden; - HUDOverlay.PlayerSettingsOverlay.State.Disabled = true; + HUDOverlay.PlayerSettingsOverlay.Expire(); } protected override void UpdateAfterChildren() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs index 52e4a6e012..f28c2a1d48 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [BackgroundDependencyLoader] private void load() { - PlayerSettingsGroups.Alpha = 0f; + PlayerSettingsGroups.Expire(); } protected override void LogoArriving(OsuLogo logo, bool resuming) diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index efd37194d3..ffcbb06fb3 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -57,7 +57,7 @@ namespace osu.Game.Screens.Play.HUD if (e.ControlPressed) { - if (e.Key == Key.H && ReplayLoaded && !State.Disabled) + if (e.Key == Key.H && ReplayLoaded) { ToggleVisibility(); return true; diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 919886cae7..2cf2555b3e 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -240,17 +240,13 @@ namespace osu.Game.Screens.Play if (e.NewValue) { - if (!PlayerSettingsOverlay.State.Disabled) - PlayerSettingsOverlay.Show(); - + PlayerSettingsOverlay.Show(); ModDisplay.FadeIn(200); KeyCounter.Margin = new MarginPadding(10) { Bottom = 30 }; } else { - if (!PlayerSettingsOverlay.State.Disabled) - PlayerSettingsOverlay.Hide(); - + PlayerSettingsOverlay.Hide(); ModDisplay.Delay(2000).FadeOut(200); KeyCounter.Margin = new MarginPadding(10); } From e7cf6b2d2337168ecfd0442e3518efa87d7d2c07 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 07:29:55 +0300 Subject: [PATCH 228/961] Expire hold-to-quit button on multi-spectator player --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index b0ea361dbb..20381e0c48 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -36,6 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); HUDOverlay.PlayerSettingsOverlay.Expire(); + HUDOverlay.HoldToQuit.Expire(); } protected override void UpdateAfterChildren() From 34c2b317e240821b5c7038fa0b3d1afb45ac3be5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 07:30:09 +0300 Subject: [PATCH 229/961] Hide song progress bar on multi-spectator player --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 2 ++ osu.Game/Screens/Play/Player.cs | 12 +++++++++++- osu.Game/Screens/Play/SongProgress.cs | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 20381e0c48..1b1dee5ae2 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -35,6 +35,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); + AllowUserSeekingState.Value = false; + AllowUserSeekingState.Disabled = true; HUDOverlay.PlayerSettingsOverlay.Expire(); HUDOverlay.HoldToQuit.Expire(); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 09eaf1c543..dc37464a61 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,6 +77,10 @@ namespace osu.Game.Screens.Play protected readonly Bindable LocalUserPlaying = new Bindable(); + protected readonly Bindable AllowUserSeekingState = new Bindable(); + + public IBindable AllowUserSeeking => AllowUserSeekingState; + public int RestartCount; [Resolved] @@ -269,7 +273,13 @@ namespace osu.Game.Screens.Play DrawableRuleset.FrameStableClock.IsCatchingUp.BindValueChanged(_ => updateSampleDisabledState()); - DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState()); + DrawableRuleset.HasReplayLoaded.BindValueChanged(r => + { + if (!AllowUserSeekingState.Disabled) + AllowUserSeekingState.Value = r.NewValue; + + updateGameplayState(); + }); // bind clock into components that require it DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index f28622f42e..8debe6243d 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play if (drawableRuleset != null) { - AllowSeeking.BindTo(drawableRuleset.HasReplayLoaded); + ((IBindable)AllowSeeking).BindTo(player.AllowUserSeeking); referenceClock = drawableRuleset.FrameStableClock; Objects = drawableRuleset.Objects; From fc22e806f44abddf493ab87bbe15f91a14e7c8c2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 07:30:24 +0300 Subject: [PATCH 230/961] Cover newly hidden/expired elements in existing test --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index ad60582ace..a9004987df 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -90,10 +90,13 @@ namespace osu.Game.Tests.Visual.Multiplayer loadSpectateScreen(false); AddUntilStep("wait for player loaders", () => this.ChildrenOfType().Count() == 2); - AddAssert("all player loader settings hidden", () => this.ChildrenOfType().All(l => l.ChildrenOfType>().Single().Alpha == 0f)); + AddAssert("all player loader settings hidden", () => this.ChildrenOfType().All(l => !l.ChildrenOfType>().Any())); AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded); - AddAssert("all player settings hidden", () => this.ChildrenOfType().All(p => p.ChildrenOfType().Single().State.Value == Visibility.Hidden)); + AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => + !p.ChildrenOfType().Any() && + !p.ChildrenOfType().Any() && + !p.ChildrenOfType().Single().ShowHandle)); } [Test] From 8fc0edb283390c9f27955a0ecc8149312692877a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 13:54:52 +0900 Subject: [PATCH 231/961] Fix some multiplayer test failures --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 4 ++++ .../Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 0ffa5209e3..01e40e0247 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -312,6 +312,8 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); + AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating); + AddStep("start match externally", () => client.StartMatch()); AddAssert("play not started", () => multiplayerScreen.IsCurrentScreen()); @@ -348,6 +350,8 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); + AddUntilStep("wait for spectating user state", () => client.LocalUser?.State == MultiplayerUserState.Spectating); + AddStep("start match externally", () => client.StartMatch()); AddStep("restore beatmap", () => diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index 955be6ca21..ea10fc1b8b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -129,6 +129,8 @@ namespace osu.Game.Tests.Visual.Multiplayer InputManager.Click(MouseButton.Left); }); + AddUntilStep("wait for spectating user state", () => Client.LocalUser?.State == MultiplayerUserState.Spectating); + AddUntilStep("wait for ready button to be enabled", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Enabled.Value); AddStep("click ready button", () => From 8fd6a9eb4b403c33d656f79bea54df49782eb562 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:01:38 +0900 Subject: [PATCH 232/961] 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 454bb46059..ecfaff0547 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e6219fcb85..9ee1ad167e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 9904946363..c378f24b69 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 755b6460b624c164f63f9e2419f38effce2124e0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 14:04:43 +0900 Subject: [PATCH 233/961] Fix multiplayer navigation test failure --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 4 ++-- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 +++++ .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 0ffa5209e3..35beefaa2a 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -25,7 +25,7 @@ using osu.Game.Screens; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; -using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; using osu.Game.Tests.Resources; @@ -396,7 +396,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } }); - AddStep("open mod overlay", () => this.ChildrenOfType().ElementAt(2).TriggerClick()); + AddStep("open mod overlay", () => this.ChildrenOfType().Single().TriggerClick()); AddStep("invoke on back button", () => multiplayerScreen.OnBackButton()); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index a53e253581..2616abf825 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -17,6 +17,7 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Match { @@ -250,5 +251,9 @@ namespace osu.Game.Screens.OnlinePlay.Match private class UserModSelectOverlay : LocalPlayerModSelectOverlay { } + + public class UserModSelectButton : PurpleTriangleButton + { + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 9fa19aaf21..a8e44dd56c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -176,7 +176,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Spacing = new Vector2(10, 0), Children = new Drawable[] { - new PurpleTriangleButton + new UserModSelectButton { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 45aca24ab2..953c687087 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -163,7 +163,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Spacing = new Vector2(10, 0), Children = new Drawable[] { - new PurpleTriangleButton + new UserModSelectButton { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From 89eded457c094701a1c4532a546cfe96df50db80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:27:28 +0900 Subject: [PATCH 234/961] Fix weird margins on loading display in lounge --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 122b30b1d2..910afb5540 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -63,6 +63,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { OsuScrollContainer scrollContainer; + Container filterContainer; + InternalChildren = new Drawable[] { new Box @@ -93,7 +95,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { new Drawable[] { - new Container + filterContainer = new Container { RelativeSizeAxes = Axes.X, Height = 70, @@ -123,13 +125,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge ScrollbarOverlapsContent = false, Child = roomsContainer = new RoomsContainer() }, - loadingLayer = new LoadingLayer(true), } }, } } }, - } + }, + loadingLayer = new LoadingLayer(true), + filterContainer.CreateProxy() }; // scroll selected room into view on selection. From 0f45155b8e1b25a7a64698af618b1dcd7cde57e7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:29:28 +0900 Subject: [PATCH 235/961] Fix remaining cases of invalid bindable operations during lease --- .../Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 3b0f2c1eba..46d9850fde 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -154,7 +154,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override bool OnClick(ClickEvent e) { - selectedRoom.Value = null; + if (!selectedRoom.Disabled) + selectedRoom.Value = null; return base.OnClick(e); } @@ -216,6 +217,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void selectNext(int direction) { + if (selectedRoom.Disabled) + return; + var visibleRooms = Rooms.AsEnumerable().Where(r => r.IsPresent); Room room; From b9721f5261c52a42e6eabec465a55e6b6d024431 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:37:43 +0900 Subject: [PATCH 236/961] Centralise screen exit logic and guard against non-current screen --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 36b86737bc..265b68afea 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -274,7 +274,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer isConnected.BindValueChanged(connected => { if (!connected.NewValue) - Schedule(this.Exit); + handleRoomLost(); }, true); currentRoom.BindValueChanged(room => @@ -284,7 +284,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // the room has gone away. // this could mean something happened during the join process, or an external connection issue occurred. // one specific scenario is where the underlying room is created, but the signalr server returns an error during the join process. this triggers a PartRoom operation (see https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs#L97) - Schedule(this.Exit); + handleRoomLost(); } }, true); } @@ -451,13 +451,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // may happen if the client is kicked or otherwise removed from the room. if (client.Room == null) { - Schedule(this.Exit); + handleRoomLost(); return; } Scheduler.AddOnce(UpdateMods); } + private void handleRoomLost() => Schedule(() => + { + if (this.IsCurrentScreen()) + this.Exit(); + else + ValidForResume = false; + }); + private void onLoadRequested() { if (BeatmapAvailability.Value.State != DownloadState.LocallyAvailable) From a1b72e7f97731b072a3a1fb204fd12310e239bdb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:41:07 +0900 Subject: [PATCH 237/961] Remove redundant array type specification --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 910afb5540..fb0b963167 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Container filterContainer; - InternalChildren = new Drawable[] + InternalChildren = new[] { new Box { From 641d57e5e1657cc8ca26aea5031e47de7d3256ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:46:28 +0900 Subject: [PATCH 238/961] Change scroll container subclass name to hopefully read better --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 14fcaa91fa..0f1ddedcf0 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.Play.HUD InternalChildren = new Drawable[] { - scroll = new ManualScrollScrollContainer + scroll = new InputDisabledScrollContainer { RelativeSizeAxes = Axes.Both, Child = Flow = new FillFlowContainer @@ -174,9 +174,9 @@ namespace osu.Game.Screens.Play.HUD sorting.Validate(); } - private class ManualScrollScrollContainer : OsuScrollContainer + private class InputDisabledScrollContainer : OsuScrollContainer { - public ManualScrollScrollContainer() + public InputDisabledScrollContainer() { ScrollbarVisible = false; } From 93574acf729981a8e925fc3edd0342bb444e56f2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:46:57 +0900 Subject: [PATCH 239/961] Fix exception messaging --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 0f1ddedcf0..312eeec949 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -82,7 +82,7 @@ namespace osu.Game.Screens.Play.HUD if (isTracked) { if (trackedScore != null) - throw new InvalidOperationException("Cannot track more than one scores."); + throw new InvalidOperationException("Cannot track more than one score."); trackedScore = drawable; } From 90755c0307b8af7de3c7c3d624be9d0b012e8d9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 14:50:59 +0900 Subject: [PATCH 240/961] Replace condition with matching precalculated bool --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 312eeec949..871555e5a3 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -142,7 +142,7 @@ namespace osu.Game.Screens.Play.HUD c.Colour = Color4.Transparent; else { - if (bottomY - fadeBottom > 0 && requiresScroll) + if (requireBottomFade) { c.Colour = ColourInfo.GradientVertical( Color4.White.Opacity(Math.Min(1 - (topY - fadeBottom) / panel_height, 1)), From 0901333ef3d1cda32dca3fe26e8513679ed01147 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 8 Aug 2021 17:20:46 +0700 Subject: [PATCH 241/961] add pinned property in comment --- osu.Game/Online/API/Requests/Responses/Comment.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/Comment.cs b/osu.Game/Online/API/Requests/Responses/Comment.cs index 05a24cec0e..32d489432d 100644 --- a/osu.Game/Online/API/Requests/Responses/Comment.cs +++ b/osu.Game/Online/API/Requests/Responses/Comment.cs @@ -58,6 +58,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"edited_by_id")] public long? EditedById { get; set; } + [JsonProperty(@"pinned")] + public bool Pinned { get; set; } + public User EditedUser { get; set; } public bool IsTopLevel => !ParentId.HasValue; From ff860b90a936d89cf0b251e8c8e866e52a884bd7 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 8 Aug 2021 17:21:02 +0700 Subject: [PATCH 242/961] add pinned test case for drawable comment --- osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 7b741accbb..5d1f3affc6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -43,6 +43,9 @@ namespace osu.Game.Tests.Visual.Online { AddStep(description, () => { + if (description == "Pinned") + comment.Pinned = true; + comment.Message = text; container.Add(new DrawableComment(comment)); }); @@ -59,6 +62,7 @@ namespace osu.Game.Tests.Visual.Online private static object[] comments = { new[] { "Plain", "This is plain comment" }, + new[] { "Pinned", "This is pinned comment" }, new[] { "Link", "Please visit https://osu.ppy.sh" }, new[] From 1859e651b67760356d5ada53fc36570cc69acaa5 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 8 Aug 2021 17:21:29 +0700 Subject: [PATCH 243/961] add pinned mark in drawable comment --- osu.Game/Overlays/Comments/DrawableComment.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 3520b15b1e..389e61bc30 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -21,6 +21,7 @@ using osu.Framework.Extensions.IEnumerableExtensions; using System.Collections.Specialized; using osu.Framework.Localisation; using osu.Game.Overlays.Comments.Buttons; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.Comments { @@ -143,6 +144,26 @@ namespace osu.Game.Overlays.Comments { AutoSizeAxes = Axes.Both }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(3, 0), + Alpha = Comment.Pinned ? 1 : 0, + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Thumbtack, + Size = new Vector2(14), + }, + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + Text = CommentsStrings.Pinned, + } + }, + }, new ParentUsername(Comment), new OsuSpriteText { From 39b13efdd58953eaf1ae0548d8be87ab89c6d68e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 13:13:28 +0700 Subject: [PATCH 244/961] add pinned comments property in comment bundle --- osu.Game/Online/API/Requests/Responses/CommentBundle.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs index d76ede67cd..0585d75f0c 100644 --- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -24,6 +24,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"included_comments")] public List IncludedComments { get; set; } + [JsonProperty(@"pinned_comments")] + public List PinnedComments { get; set; } + private List userVotes; [JsonProperty(@"user_votes")] From c5ee8753b43a3713073707aeb799d20fc1d82378 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 09:20:52 +0300 Subject: [PATCH 245/961] Notify users to read OpenTabletDriver's FAQ when tablet not detected --- .../Settings/Sections/Input/TabletSettings.cs | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index c7342c251d..7595ca59cb 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -9,9 +10,12 @@ using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Threading; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; using osu.Game.Localisation; +using osu.Game.Online.Chat; namespace osu.Game.Overlays.Settings.Sections.Input { @@ -52,7 +56,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input private FillFlowContainer mainSettings; - private OsuSpriteText noTabletMessage; + private FillFlowContainer noTabletMessage; protected override LocalisableString Header => TabletSettingsStrings.Tablet; @@ -62,7 +66,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours) { Children = new Drawable[] { @@ -73,12 +77,41 @@ namespace osu.Game.Overlays.Settings.Sections.Input Origin = Anchor.TopCentre, Current = tabletHandler.Enabled }, - noTabletMessage = new OsuSpriteText + noTabletMessage = new FillFlowContainer { - Text = TabletSettingsStrings.NoTabletDetected, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS } + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }, + Spacing = new Vector2(5f), + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Text = TabletSettingsStrings.NoTabletDetected, + }, + new LinkFlowContainer + { + TextAnchor = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }.With(t => + { + t.NewLine(); + t.AddText("If your tablet is not getting detected properly,", s => s.Colour = colours.Yellow); + t.NewParagraph(); + t.AddText("read ", s => s.Colour = colours.Yellow); + t.AddLink("the driver's FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows + ? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ" + : @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ"); + + t.AddText(" to troubleshoot the problem further.", s => s.Colour = colours.Yellow); + }), + } }, mainSettings = new FillFlowContainer { From 5cec50bdd14ad16b4b07e14605cb9d5d3dd2eddf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 15:24:43 +0900 Subject: [PATCH 246/961] Add comment mentioning why event bindings are not unbound --- osu.Game/Screens/OnlinePlay/Header.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Header.cs b/osu.Game/Screens/OnlinePlay/Header.cs index 58c67a51e8..b0db9256f5 100644 --- a/osu.Game/Screens/OnlinePlay/Header.cs +++ b/osu.Game/Screens/OnlinePlay/Header.cs @@ -35,6 +35,7 @@ namespace osu.Game.Screens.OnlinePlay Origin = Anchor.CentreLeft, }; + // unnecessary to unbind these as this header has the same lifetime as the screen stack we are attaching to. stack.ScreenPushed += (_, __) => updateSubScreenTitle(); stack.ScreenExited += (_, __) => updateSubScreenTitle(); } From 3b6a8a2bae61e342da76a735cc49c97cf9c5d99d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 15:24:53 +0900 Subject: [PATCH 247/961] Rename background sprite and reduce load delay --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 978b35e4b1..c2ad0285b1 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -108,7 +108,7 @@ namespace osu.Game.Screens.OnlinePlay { RelativeSizeAxes = Axes.Both, BlurSigma = new Vector2(10), - Child = new HeaderBackgroundSprite + Child = new BeatmapBackgroundSprite { RelativeSizeAxes = Axes.Both } @@ -304,13 +304,13 @@ namespace osu.Game.Screens.OnlinePlay } } - private class HeaderBackgroundSprite : OnlinePlayBackgroundSprite + private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite { protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; private class BackgroundSprite : UpdateableBeatmapBackgroundSprite { - protected override double TransformDuration => 200; + protected override double LoadDelay => 200; } } From 543f6039e24071c28e18ae838185d863257638cb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 09:26:53 +0300 Subject: [PATCH 248/961] Display on Windows and Linux only --- .../Settings/Sections/Input/TabletSettings.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 7595ca59cb..9ed85e44ec 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -101,15 +101,18 @@ namespace osu.Game.Overlays.Settings.Sections.Input AutoSizeAxes = Axes.Y, }.With(t => { - t.NewLine(); - t.AddText("If your tablet is not getting detected properly,", s => s.Colour = colours.Yellow); - t.NewParagraph(); - t.AddText("read ", s => s.Colour = colours.Yellow); - t.AddLink("the driver's FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows - ? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ" - : @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ"); + if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) + { + t.NewLine(); + t.AddText("If your tablet is not getting detected properly,", s => s.Colour = colours.Yellow); + t.NewParagraph(); + t.AddText("read ", s => s.Colour = colours.Yellow); + t.AddLink("the driver's FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows + ? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ" + : @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ"); - t.AddText(" to troubleshoot the problem further.", s => s.Colour = colours.Yellow); + t.AddText(" to troubleshoot the problem further.", s => s.Colour = colours.Yellow); + } }), } }, From dd7ca4b77b45ae0f69078afd1fdbedf7e82cad80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 15:35:45 +0900 Subject: [PATCH 249/961] Increase "create room" button height --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 1c28405e40..7249ccdd93 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -30,8 +30,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [Cached] public abstract class LoungeSubScreen : OnlinePlaySubScreen { - private const float button_height = 25; - public override string Title => "Lounge"; protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -93,7 +91,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge RowDimensions = new[] { new Dimension(GridSizeMode.Absolute, Header.HEIGHT), - new Dimension(GridSizeMode.Absolute, button_height), + new Dimension(GridSizeMode.Absolute, 25), new Dimension(GridSizeMode.Absolute, 20) }, Content = new[] @@ -118,7 +116,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { Buttons.WithChild(CreateNewRoomButton().With(d => { - d.Size = new Vector2(150, button_height); + d.Anchor = Anchor.BottomLeft; + d.Origin = Anchor.BottomLeft; + d.Size = new Vector2(150, 37.5f); d.Action = () => Open(); })), new FillFlowContainer From f9f3339885152bed5bf6eaf46ba4bbf9e024b396 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:14:23 +0900 Subject: [PATCH 250/961] Fix vertical offset not being handled correctly during score panel detach process --- .../Multiplayer/MultiplayerTeamResultsScreen.cs | 6 +++--- osu.Game/Screens/Ranking/ResultsScreen.cs | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs index e98898b9da..14a779dedf 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerTeamResultsScreen.cs @@ -46,9 +46,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { const float winner_background_half_height = 250; - ScorePanelList.Anchor = ScorePanelList.Origin = Anchor.TopCentre; - ScorePanelList.Scale = new Vector2(0.9f); - ScorePanelList.Y = 75; + VerticalScrollContent.Anchor = VerticalScrollContent.Origin = Anchor.TopCentre; + VerticalScrollContent.Scale = new Vector2(0.9f); + VerticalScrollContent.Y = 75; var redScore = teamScores.First().Value; var blueScore = teamScores.Last().Value; diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index b458d7c17f..d44d1f2cc9 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -40,6 +40,8 @@ namespace osu.Game.Screens.Ranking protected ScorePanelList ScorePanelList { get; private set; } + protected VerticalScrollContainer VerticalScrollContent { get; private set; } + [Resolved(CanBeNull = true)] private Player player { get; set; } @@ -77,7 +79,7 @@ namespace osu.Game.Screens.Ranking { new Drawable[] { - new VerticalScrollContainer + VerticalScrollContent = new VerticalScrollContainer { RelativeSizeAxes = Axes.Both, ScrollbarVisible = false, @@ -343,7 +345,7 @@ namespace osu.Game.Screens.Ranking { } - private class VerticalScrollContainer : OsuScrollContainer + protected class VerticalScrollContainer : OsuScrollContainer { protected override Container Content => content; @@ -351,6 +353,8 @@ namespace osu.Game.Screens.Ranking public VerticalScrollContainer() { + Masking = false; + base.Content.Add(content = new Container { RelativeSizeAxes = Axes.X }); } From cd842ccef8f1221eb59a71defb2dc19348e9ccd9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 10:15:50 +0300 Subject: [PATCH 251/961] Improve message Co-authored-by: Dean Herbert --- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 9ed85e44ec..af94dcdaca 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -104,14 +104,11 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) { t.NewLine(); - t.AddText("If your tablet is not getting detected properly,", s => s.Colour = colours.Yellow); - t.NewParagraph(); - t.AddText("read ", s => s.Colour = colours.Yellow); - t.AddLink("the driver's FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows + t.AddText("If your tablet is not detected, please read ", s => s.Colour = colours.Yellow); + t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ" : @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ"); - - t.AddText(" to troubleshoot the problem further.", s => s.Colour = colours.Yellow); + t.AddText(" for troubleshooting steps.", s => s.Colour = colours.Yellow); } }), } From db52549152f56e28cf22bb018ff22f32d19bb8de Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:20:53 +0900 Subject: [PATCH 252/961] Move below everything rather than proxying (works better with new design) --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 43da62d466..ceec609f6d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -75,10 +75,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge OsuScrollContainer scrollContainer; - Container filterContainer; - InternalChildren = new[] { + loadingLayer = new LoadingLayer(true), new Container { RelativeSizeAxes = Axes.Both, @@ -159,8 +158,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge } }, }, - loadingLayer = new LoadingLayer(true), - filterContainer.CreateProxy() }; // scroll selected room into view on selection. From c1d67976e6accf5ca2980a6aa116e791e8e9432a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:29:36 +0900 Subject: [PATCH 253/961] Rename const, add xmldoc and make protected --- osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs | 4 ++-- osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs | 2 ++ osu.Game/OsuGame.cs | 9 ++++++--- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index 21db7e2802..e58f85b0b3 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Menus public void TestScreenOffsettingOnSettingsOverlay() { AddStep("open settings", () => Game.Settings.Show()); - AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO); AddStep("hide settings", () => Game.Settings.Hide()); AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); @@ -33,7 +33,7 @@ namespace osu.Game.Tests.Visual.Menus public void TestScreenOffsettingOnNotificationOverlay() { AddStep("open notifications", () => Game.Notifications.Show()); - AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * OsuGame.SCREEN_OFFSET_RATIO); + AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO); AddStep("hide notifications", () => Game.Notifications.Hide()); AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs index 5cd55ed233..c9a1471e41 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs @@ -96,6 +96,8 @@ namespace osu.Game.Tests.Visual.Navigation public class TestOsuGame : OsuGame { + public new const float SIDE_OVERLAY_OFFSET_RATIO = OsuGame.SIDE_OVERLAY_OFFSET_RATIO; + public new ScreenStack ScreenStack => base.ScreenStack; public new BackButton BackButton => base.BackButton; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index f92f7e9e8c..6d76fec7c1 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -64,7 +64,10 @@ namespace osu.Game /// public class OsuGame : OsuGameBase, IKeyBindingHandler { - public const float SCREEN_OFFSET_RATIO = 0.125f; + /// + /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). + /// + protected const float SIDE_OVERLAY_OFFSET_RATIO = 0.125f; public Toolbar Toolbar; @@ -1016,9 +1019,9 @@ namespace osu.Game var horizontalOffset = 0f; if (Settings.IsLoaded && Settings.IsPresent) - horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SCREEN_OFFSET_RATIO; + horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO; if (Notifications.IsLoaded && Notifications.IsPresent) - horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SCREEN_OFFSET_RATIO; + horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SIDE_OVERLAY_OFFSET_RATIO; ScreenOffsetContainer.X = horizontalOffset; From da18c399e2d7cd531e019c8b140155a02135a4dd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:33:00 +0900 Subject: [PATCH 254/961] Remove unnecessary `IsPresent` override --- osu.Game/Overlays/SettingsPanel.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 8b953e8655..f1c41c4b50 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -42,12 +42,6 @@ namespace osu.Game.Overlays protected override Container Content => ContentContainer; - /// - /// The always needs to be present for to process transforms while overlay is masked away. - /// todo: there may be a better solution for this and the existing , likely requires a refactor. - /// - public override bool IsPresent => true; - protected Sidebar Sidebar; private SidebarButton selectedSidebarButton; From 93b97e5110774787b27ba91cb595158a65491cbf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:35:22 +0900 Subject: [PATCH 255/961] Adjust ratio to match previous behaviour --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 6d76fec7c1..fb682e0909 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -67,7 +67,7 @@ namespace osu.Game /// /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). /// - protected const float SIDE_OVERLAY_OFFSET_RATIO = 0.125f; + protected const float SIDE_OVERLAY_OFFSET_RATIO = 0.05f; public Toolbar Toolbar; From 5a60b39643b172dd679cd5e81712c99422fff024 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 13 Aug 2021 16:42:58 +0900 Subject: [PATCH 256/961] Remove unnecessary delimiters from song select filter splitting --- osu.Game/Screens/Select/FilterCriteria.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs index b9e912df8e..f47bc5f466 100644 --- a/osu.Game/Screens/Select/FilterCriteria.cs +++ b/osu.Game/Screens/Select/FilterCriteria.cs @@ -56,7 +56,7 @@ namespace osu.Game.Screens.Select set { searchText = value; - SearchTerms = searchText.Split(new[] { ',', ' ', '!' }, StringSplitOptions.RemoveEmptyEntries).ToArray(); + SearchTerms = searchText.Split(' ', StringSplitOptions.RemoveEmptyEntries).ToArray(); SearchNumber = null; From f43ab323ffad425b250c0ed761c8c00c8895349b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 11:12:26 +0300 Subject: [PATCH 257/961] Add shared class for notice text in settings --- .../Settings/Sections/Input/TabletSettings.cs | 9 +++----- osu.Game/Overlays/Settings/SettingsItem.cs | 8 +------ .../Overlays/Settings/SettingsNoticeText.cs | 21 +++++++++++++++++++ 3 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Overlays/Settings/SettingsNoticeText.cs diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index af94dcdaca..2816eb7037 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -11,7 +11,6 @@ using osu.Framework.Localisation; using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osuTK; using osu.Game.Localisation; @@ -92,23 +91,21 @@ namespace osu.Game.Overlays.Settings.Sections.Input Origin = Anchor.TopCentre, Text = TabletSettingsStrings.NoTabletDetected, }, - new LinkFlowContainer + new SettingsNoticeText { TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, }.With(t => { if (RuntimeInfo.OS == RuntimeInfo.Platform.Windows || RuntimeInfo.OS == RuntimeInfo.Platform.Linux) { t.NewLine(); - t.AddText("If your tablet is not detected, please read ", s => s.Colour = colours.Yellow); + t.AddText("If your tablet is not detected, please read "); t.AddLink("this FAQ", LinkAction.External, RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Windows-FAQ" : @"https://github.com/OpenTabletDriver/OpenTabletDriver/wiki/Linux-FAQ"); - t.AddText(" for troubleshooting steps.", s => s.Colour = colours.Yellow); + t.AddText(" for troubleshooting steps."); } }), } diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index bd17c02af9..5d25605360 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -73,13 +73,7 @@ namespace osu.Game.Overlays.Settings return; // construct lazily for cases where the label is not needed (may be provided by the Control). - FlowContent.Add(warningText = new OsuTextFlowContainer - { - Colour = colours.Yellow, - Margin = new MarginPadding { Bottom = 5 }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }); + FlowContent.Add(warningText = new SettingsNoticeText { Margin = new MarginPadding { Bottom = 5 } }); } warningText.Alpha = hasValue ? 0 : 1; diff --git a/osu.Game/Overlays/Settings/SettingsNoticeText.cs b/osu.Game/Overlays/Settings/SettingsNoticeText.cs new file mode 100644 index 0000000000..6bb4a3f11c --- /dev/null +++ b/osu.Game/Overlays/Settings/SettingsNoticeText.cs @@ -0,0 +1,21 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Settings +{ + public class SettingsNoticeText : LinkFlowContainer + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Colour = colours.Yellow; + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + } +} From 8910781bcdb4dac3a18e17c1962c6dd34421b550 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 17:39:09 +0900 Subject: [PATCH 258/961] Move listing polling component to LoungeSubScreen --- .../TestSceneLoungeRoomsContainer.cs | 2 +- .../TestSceneMultiplayerRoomManager.cs | 314 +++++++++--------- .../TestScenePlaylistsMatchSettingsOverlay.cs | 12 + osu.Game/Online/Rooms/Room.cs | 2 +- .../Components/ListingPollingComponent.cs | 23 +- .../OnlinePlay/Components/RoomManager.cs | 73 ++-- .../Components/RoomPollingComponent.cs | 15 +- .../Components/SelectionPollingComponent.cs | 14 +- osu.Game/Screens/OnlinePlay/IRoomManager.cs | 11 +- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 53 ++- .../OnlinePlay/Multiplayer/Multiplayer.cs | 30 -- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 33 ++ .../Multiplayer/MultiplayerMatchSubScreen.cs | 9 +- .../Multiplayer/MultiplayerRoomManager.cs | 73 ---- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 22 +- .../Screens/OnlinePlay/Playlists/Playlists.cs | 39 --- .../Playlists/PlaylistsLoungeSubScreen.cs | 3 + .../Playlists/PlaylistsRoomManager.cs | 21 -- .../Visual/OnlinePlay/BasicTestRoomManager.cs | 10 +- 19 files changed, 308 insertions(+), 451 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index bcbdcd2a4f..f3d961a646 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -74,7 +74,7 @@ namespace osu.Game.Tests.Visual.Multiplayer var room = RoomManager.Rooms[1]; RoomManager.RemoveRoom(room); - RoomManager.AddRoom(room); + RoomManager.AddOrUpdateRoom(room); }); AddAssert("no selection", () => checkRoomSelected(null)); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs index b17427a30b..15e9112c47 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs @@ -1,157 +1,157 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using NUnit.Framework; -using osu.Framework.Testing; -using osu.Game.Online.Rooms; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Tests.Beatmaps; -using osu.Game.Tests.Visual.OnlinePlay; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - [HeadlessTest] - public class TestSceneMultiplayerRoomManager : MultiplayerTestScene - { - protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies(); - - public TestSceneMultiplayerRoomManager() - : base(false) - { - } - - [Test] - public void TestPollsInitially() - { - AddStep("create room manager with a few rooms", () => - { - RoomManager.CreateRoom(createRoom(r => r.Name.Value = "1")); - RoomManager.PartRoom(); - RoomManager.CreateRoom(createRoom(r => r.Name.Value = "2")); - RoomManager.PartRoom(); - RoomManager.ClearRooms(); - }); - - AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); - AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); - } - - [Test] - public void TestRoomsClearedOnDisconnection() - { - AddStep("create room manager with a few rooms", () => - { - RoomManager.CreateRoom(createRoom()); - RoomManager.PartRoom(); - RoomManager.CreateRoom(createRoom()); - RoomManager.PartRoom(); - }); - - AddStep("disconnect", () => Client.Disconnect()); - - AddAssert("rooms cleared", () => ((RoomManager)RoomManager).Rooms.Count == 0); - AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); - } - - [Test] - public void TestRoomsPolledOnReconnect() - { - AddStep("create room manager with a few rooms", () => - { - RoomManager.CreateRoom(createRoom()); - RoomManager.PartRoom(); - RoomManager.CreateRoom(createRoom()); - RoomManager.PartRoom(); - }); - - AddStep("disconnect", () => Client.Disconnect()); - AddStep("connect", () => Client.Connect()); - - AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); - AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); - } - - [Test] - public void TestRoomsNotPolledWhenJoined() - { - AddStep("create room manager with a room", () => - { - RoomManager.CreateRoom(createRoom()); - RoomManager.ClearRooms(); - }); - - AddAssert("manager not polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 0); - AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); - } - - [Test] - public void TestMultiplayerRoomJoinedWhenCreated() - { - AddStep("create room manager with a room", () => - { - RoomManager.CreateRoom(createRoom()); - }); - - AddUntilStep("multiplayer room joined", () => Client.Room != null); - } - - [Test] - public void TestMultiplayerRoomPartedWhenAPIRoomParted() - { - AddStep("create room manager with a room", () => - { - RoomManager.CreateRoom(createRoom()); - RoomManager.PartRoom(); - }); - - AddAssert("multiplayer room parted", () => Client.Room == null); - } - - [Test] - public void TestMultiplayerRoomJoinedWhenAPIRoomJoined() - { - AddStep("create room manager with a room", () => - { - var r = createRoom(); - RoomManager.CreateRoom(r); - RoomManager.PartRoom(); - RoomManager.JoinRoom(r); - }); - - AddUntilStep("multiplayer room joined", () => Client.Room != null); - } - - private Room createRoom(Action initFunc = null) - { - var room = new Room - { - Name = - { - Value = "test room" - }, - Playlist = - { - new PlaylistItem - { - Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, - Ruleset = { Value = Ruleset.Value } - } - } - }; - - initFunc?.Invoke(room); - return room; - } - - private class TestDependencies : MultiplayerTestSceneDependencies - { - public TestDependencies() - { - // Need to set these values as early as possible. - RoomManager.TimeBetweenListingPolls.Value = 1; - RoomManager.TimeBetweenSelectionPolls.Value = 1; - } - } - } -} +// // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// // See the LICENCE file in the repository root for full licence text. +// +// using System; +// using NUnit.Framework; +// using osu.Framework.Testing; +// using osu.Game.Online.Rooms; +// using osu.Game.Screens.OnlinePlay.Components; +// using osu.Game.Tests.Beatmaps; +// using osu.Game.Tests.Visual.OnlinePlay; +// +// namespace osu.Game.Tests.Visual.Multiplayer +// { +// [HeadlessTest] +// public class TestSceneMultiplayerRoomManager : MultiplayerTestScene +// { +// protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies(); +// +// public TestSceneMultiplayerRoomManager() +// : base(false) +// { +// } +// +// [Test] +// public void TestPollsInitially() +// { +// AddStep("create room manager with a few rooms", () => +// { +// RoomManager.CreateRoom(createRoom(r => r.Name.Value = "1")); +// RoomManager.PartRoom(); +// RoomManager.CreateRoom(createRoom(r => r.Name.Value = "2")); +// RoomManager.PartRoom(); +// RoomManager.ClearRooms(); +// }); +// +// AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); +// AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); +// } +// +// [Test] +// public void TestRoomsClearedOnDisconnection() +// { +// AddStep("create room manager with a few rooms", () => +// { +// RoomManager.CreateRoom(createRoom()); +// RoomManager.PartRoom(); +// RoomManager.CreateRoom(createRoom()); +// RoomManager.PartRoom(); +// }); +// +// AddStep("disconnect", () => Client.Disconnect()); +// +// AddAssert("rooms cleared", () => ((RoomManager)RoomManager).Rooms.Count == 0); +// AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); +// } +// +// [Test] +// public void TestRoomsPolledOnReconnect() +// { +// AddStep("create room manager with a few rooms", () => +// { +// RoomManager.CreateRoom(createRoom()); +// RoomManager.PartRoom(); +// RoomManager.CreateRoom(createRoom()); +// RoomManager.PartRoom(); +// }); +// +// AddStep("disconnect", () => Client.Disconnect()); +// AddStep("connect", () => Client.Connect()); +// +// AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); +// AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); +// } +// +// [Test] +// public void TestRoomsNotPolledWhenJoined() +// { +// AddStep("create room manager with a room", () => +// { +// RoomManager.CreateRoom(createRoom()); +// RoomManager.ClearRooms(); +// }); +// +// AddAssert("manager not polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 0); +// AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); +// } +// +// [Test] +// public void TestMultiplayerRoomJoinedWhenCreated() +// { +// AddStep("create room manager with a room", () => +// { +// RoomManager.CreateRoom(createRoom()); +// }); +// +// AddUntilStep("multiplayer room joined", () => Client.Room != null); +// } +// +// [Test] +// public void TestMultiplayerRoomPartedWhenAPIRoomParted() +// { +// AddStep("create room manager with a room", () => +// { +// RoomManager.CreateRoom(createRoom()); +// RoomManager.PartRoom(); +// }); +// +// AddAssert("multiplayer room parted", () => Client.Room == null); +// } +// +// [Test] +// public void TestMultiplayerRoomJoinedWhenAPIRoomJoined() +// { +// AddStep("create room manager with a room", () => +// { +// var r = createRoom(); +// RoomManager.CreateRoom(r); +// RoomManager.PartRoom(); +// RoomManager.JoinRoom(r); +// }); +// +// AddUntilStep("multiplayer room joined", () => Client.Room != null); +// } +// +// private Room createRoom(Action initFunc = null) +// { +// var room = new Room +// { +// Name = +// { +// Value = "test room" +// }, +// Playlist = +// { +// new PlaylistItem +// { +// Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, +// Ruleset = { Value = Ruleset.Value } +// } +// } +// }; +// +// initFunc?.Invoke(room); +// return room; +// } +// +// private class TestDependencies : MultiplayerTestSceneDependencies +// { +// public TestDependencies() +// { +// // Need to set these values as early as possible. +// RoomManager.TimeBetweenListingPolls.Value = 1; +// RoomManager.TimeBetweenSelectionPolls.Value = 1; +// } +// } +// } +// } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index cdc655500d..79af2d3099 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -141,6 +141,18 @@ namespace osu.Game.Tests.Visual.Playlists public IBindableList Rooms => null; + public void AddOrUpdateRoom(Room room) + { + } + + public void RemoveRoom(Room room) + { + } + + public void ClearRooms() + { + } + public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) { if (CreateRequested == null) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 4bd5b1a788..364336783d 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -134,7 +134,7 @@ namespace osu.Game.Online.Rooms /// The position of this in the list. This is not read from or written to the API. /// [JsonIgnore] - public readonly Bindable Position = new Bindable(-1); + public readonly Bindable Position = new Bindable(-1); public Room() { diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index e50784fcbe..f686326d08 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.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 System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -14,6 +15,9 @@ namespace osu.Game.Screens.OnlinePlay.Components /// public class ListingPollingComponent : RoomPollingComponent { + public IBindable HasPolledOnce => hasPolledOnce; + private readonly Bindable hasPolledOnce = new Bindable(); + [Resolved] private Bindable currentFilter { get; set; } @@ -25,7 +29,9 @@ namespace osu.Game.Screens.OnlinePlay.Components { currentFilter.BindValueChanged(_ => { - NotifyRoomsReceived(null); + RoomManager.ClearRooms(); + hasPolledOnce.Value = false; + if (IsLoaded) PollImmediately(); }); @@ -45,17 +51,16 @@ namespace osu.Game.Screens.OnlinePlay.Components pollReq.Success += result => { - for (int i = 0; i < result.Count; i++) + foreach (var existing in RoomManager.Rooms.ToArray()) { - if (result[i].RoomID.Value == selectedRoom.Value?.RoomID.Value) - { - // The listing request always has less information than the opened room, so don't include it. - result[i] = selectedRoom.Value; - break; - } + if (result.All(r => r.RoomID.Value != existing.RoomID.Value)) + RoomManager.RemoveRoom(existing); } - NotifyRoomsReceived(result); + foreach (var incoming in result) + RoomManager.AddOrUpdateRoom(incoming); + + hasPolledOnce.Value = true; tcs.SetResult(true); }; diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs index 422576648c..ab92adcac7 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs @@ -8,7 +8,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Game.Beatmaps; using osu.Game.Online.API; @@ -17,15 +16,12 @@ using osu.Game.Rulesets; namespace osu.Game.Screens.OnlinePlay.Components { - public abstract class RoomManager : CompositeDrawable, IRoomManager + public class RoomManager : Component, IRoomManager { public event Action RoomsUpdated; private readonly BindableList rooms = new BindableList(); - public IBindable InitialRoomsReceived => initialRoomsReceived; - private readonly Bindable initialRoomsReceived = new Bindable(); - public IBindableList Rooms => rooms; protected IBindable JoinedRoom => joinedRoom; @@ -40,15 +36,9 @@ namespace osu.Game.Screens.OnlinePlay.Components [Resolved] private IAPIProvider api { get; set; } - protected RoomManager() + public RoomManager() { RelativeSizeAxes = Axes.Both; - - InternalChildren = CreatePollingComponents().Select(p => - { - p.RoomsReceived = onRoomsReceived; - return p; - }).ToList(); } protected override void Dispose(bool isDisposing) @@ -118,56 +108,41 @@ namespace osu.Game.Screens.OnlinePlay.Components private readonly HashSet ignoredRooms = new HashSet(); - private void onRoomsReceived(List received) + public void AddOrUpdateRoom(Room room) { - if (received == null) - { - ClearRooms(); + Debug.Assert(room.RoomID.Value != null); + + if (ignoredRooms.Contains(room.RoomID.Value.Value)) return; - } - // Remove past matches - foreach (var r in rooms.ToList()) + room.Position.Value = -room.RoomID.Value.Value; + + try { - if (received.All(e => e.RoomID.Value != r.RoomID.Value)) - rooms.Remove(r); + update(room, room); + addRoom(room); } - - for (int i = 0; i < received.Count; i++) + catch (Exception ex) { - var room = received[i]; + Logger.Error(ex, $"Failed to update room: {room.Name.Value}."); - Debug.Assert(room.RoomID.Value != null); - - if (ignoredRooms.Contains(room.RoomID.Value.Value)) - continue; - - room.Position.Value = i; - - try - { - update(room, room); - addRoom(room); - } - catch (Exception ex) - { - Logger.Error(ex, $"Failed to update room: {room.Name.Value}."); - - ignoredRooms.Add(room.RoomID.Value.Value); - rooms.Remove(room); - } + ignoredRooms.Add(room.RoomID.Value.Value); + rooms.Remove(room); } - RoomsUpdated?.Invoke(); - initialRoomsReceived.Value = true; + notifyRoomsUpdated(); } - protected void RemoveRoom(Room room) => rooms.Remove(room); + public void RemoveRoom(Room room) + { + rooms.Remove(room); + notifyRoomsUpdated(); + } - protected void ClearRooms() + public void ClearRooms() { rooms.Clear(); - initialRoomsReceived.Value = false; + notifyRoomsUpdated(); } /// @@ -196,6 +171,6 @@ namespace osu.Game.Screens.OnlinePlay.Components existing.CopyFrom(room); } - protected abstract IEnumerable CreatePollingComponents(); + private void notifyRoomsUpdated() => Scheduler.AddOnce(() => RoomsUpdated?.Invoke()); } } diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs index b2ea3a05d6..95b4c4284c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs @@ -1,29 +1,18 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; using osu.Framework.Allocation; using osu.Game.Online; using osu.Game.Online.API; -using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components { public abstract class RoomPollingComponent : PollingComponent { - /// - /// Invoked when any s have been received from the API. - /// - /// Any s present locally but not returned by this event are to be removed from display. - /// If null, the display of local rooms is reset to an initial state. - /// - /// - public Action> RoomsReceived; - [Resolved] protected IAPIProvider API { get; private set; } - protected void NotifyRoomsReceived(List rooms) => RoomsReceived?.Invoke(rooms); + [Resolved] + protected IRoomManager RoomManager { get; set; } } } diff --git a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs index dcf3c94b76..88d9469f8c 100644 --- a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -48,17 +46,7 @@ namespace osu.Game.Screens.OnlinePlay.Components pollReq.Success += result => { - // existing rooms need to be ordered by their position because the received of NotifyRoomsReceives expects to be able to sort them based on this order. - var rooms = new List(roomManager.Rooms.OrderBy(r => r.Position.Value)); - - int index = rooms.FindIndex(r => r.RoomID.Value == result.RoomID.Value); - - if (index < 0) - return; - - rooms[index] = result; - - NotifyRoomsReceived(rooms); + RoomManager.AddOrUpdateRoom(result); tcs.SetResult(true); }; diff --git a/osu.Game/Screens/OnlinePlay/IRoomManager.cs b/osu.Game/Screens/OnlinePlay/IRoomManager.cs index 34c1393ff1..baf84e25f9 100644 --- a/osu.Game/Screens/OnlinePlay/IRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/IRoomManager.cs @@ -18,16 +18,17 @@ namespace osu.Game.Screens.OnlinePlay /// event Action RoomsUpdated; - /// - /// Whether an initial listing of rooms has been received. - /// - IBindable InitialRoomsReceived { get; } - /// /// All the active s. /// IBindableList Rooms { get; } + void AddOrUpdateRoom(Room room); + + void RemoveRoom(Room room); + + void ClearRooms(); + /// /// Creates a new . /// diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 7249ccdd93..50f7baa44c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -12,14 +12,17 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Framework.Logging; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Input; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Users; @@ -41,10 +44,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge AutoSizeAxes = Axes.Both }; - private readonly IBindable initialRoomsReceived = new Bindable(); - private readonly IBindable operationInProgress = new Bindable(); - - private LoadingLayer loadingLayer; + protected ListingPollingComponent ListingPollingComponent { get; private set; } [Resolved] private Bindable selectedRoom { get; set; } @@ -61,9 +61,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [Resolved] private IBindable ruleset { get; set; } + [Resolved(CanBeNull = true)] + private IdleTracker idleTracker { get; set; } + [CanBeNull] private IDisposable joiningRoomOperation { get; set; } + private readonly IBindable operationInProgress = new Bindable(); + private readonly IBindable isIdle = new BindableBool(); + private LoadingLayer loadingLayer; private RoomsContainer roomsContainer; private SearchTextBox searchTextBox; private Dropdown statusDropdown; @@ -77,6 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { + ListingPollingComponent = CreatePollingComponent(), new Container { RelativeSizeAxes = Axes.Both, @@ -176,8 +183,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced()); ruleset.BindValueChanged(_ => UpdateFilter()); - initialRoomsReceived.BindTo(RoomManager.InitialRoomsReceived); - initialRoomsReceived.BindValueChanged(_ => updateLoadingLayer()); + ListingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); + + if (idleTracker != null) + { + isIdle.BindTo(idleTracker.IsIdle); + isIdle.BindValueChanged(_ => updatePollingRate(), true); + } if (ongoingOperationTracker != null) { @@ -231,7 +243,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public override void OnEntering(IScreen last) { base.OnEntering(last); - onReturning(); } @@ -266,11 +277,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void onReturning() { + updatePollingRate(); searchTextBox.HoldFocus = true; } private void onLeaving() { + updatePollingRate(); searchTextBox.HoldFocus = false; // ensure any password prompt is dismissed. @@ -316,6 +329,24 @@ namespace osu.Game.Screens.OnlinePlay.Lounge this.Push(CreateRoomSubScreen(room)); } + private void updateLoadingLayer() + { + if (operationInProgress.Value || !ListingPollingComponent.HasPolledOnce.Value) + loadingLayer.Show(); + else + loadingLayer.Hide(); + } + + private void updatePollingRate() + { + if (!this.IsCurrentScreen()) + ListingPollingComponent.TimeBetweenPolls.Value = 0; + else + ListingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; + + Logger.Log($"Polling adjusted (listing: {ListingPollingComponent.TimeBetweenPolls.Value})"); + } + protected abstract OsuButton CreateNewRoomButton(); /// @@ -326,13 +357,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected abstract RoomSubScreen CreateRoomSubScreen(Room room); - private void updateLoadingLayer() - { - if (operationInProgress.Value || !initialRoomsReceived.Value) - loadingLayer.Show(); - else - loadingLayer.Hide(); - } + protected abstract ListingPollingComponent CreatePollingComponent(); private class LoungeSearchTextBox : SearchTextBox { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs index 45928505bb..58b5b7bbeb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Multiplayer.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; -using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Online.Multiplayer; using osu.Game.Screens.OnlinePlay.Components; @@ -23,35 +22,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer client.ChangeState(MultiplayerUserState.Idle); } - protected override void UpdatePollingRate(bool isIdle) - { - var multiplayerRoomManager = (MultiplayerRoomManager)RoomManager; - - if (!this.IsCurrentScreen()) - { - multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; - } - else - { - switch (CurrentSubScreen) - { - case LoungeSubScreen _: - multiplayerRoomManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; - break; - - // Don't poll inside the match or anywhere else. - default: - multiplayerRoomManager.TimeBetweenListingPolls.Value = 0; - multiplayerRoomManager.TimeBetweenSelectionPolls.Value = 0; - break; - } - } - - Logger.Log($"Polling adjusted (listing: {multiplayerRoomManager.TimeBetweenListingPolls.Value}, selection: {multiplayerRoomManager.TimeBetweenSelectionPolls.Value})"); - } - protected override string ScreenTitle => "Multiplayer"; protected override RoomManager CreateRoomManager() => new MultiplayerRoomManager(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index ad7882abc2..db6096e93b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -1,12 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Threading.Tasks; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Logging; +using osu.Framework.Screens; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Multiplayer; using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; @@ -21,6 +25,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + ListingPollingComponent.PollImmediately(); + } + protected override FilterCriteria CreateFilterCriteria() { var criteria = base.CreateFilterCriteria(); @@ -39,6 +49,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); + protected override ListingPollingComponent CreatePollingComponent() => new MultiplayerListingPollingComponent(); + protected override void OpenNewRoom(Room room) { if (client?.IsConnected.Value != true) @@ -49,5 +61,26 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.OpenNewRoom(room); } + + private class MultiplayerListingPollingComponent : ListingPollingComponent + { + public readonly IBindable AllowPolling = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + AllowPolling.BindValueChanged(allowPolling => + { + if (!allowPolling.NewValue) + return; + + if (IsLoaded) + PollImmediately(); + }); + } + + protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); + } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index a8e44dd56c..ec011634b1 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -49,9 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private OngoingOperationTracker ongoingOperationTracker { get; set; } [Resolved] - private Bindable currentRoom { get; set; } - - private MultiplayerMatchSettingsOverlay settingsOverlay; + private Bindable currentRoom { get; set; } // Todo: This should not exist. private readonly IBindable isConnected = new Bindable(); @@ -59,6 +57,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private IDisposable readyClickOperation; private GridContainer mainContent; + private MultiplayerMatchSettingsOverlay settingsOverlay; public MultiplayerMatchSubScreen(Room room) { @@ -324,6 +323,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override bool OnExiting(IScreen next) { + // We don't know whether we're the only participant in the room, and whether the room will close after we leave it as a result. + // To work around this, temporarily remove the room until the next listing poll retrieves it. + RoomManager?.RemoveRoom(currentRoom.Value); + // the room may not be left immediately after a disconnection due to async flow, // so checking the IsConnected status is also required. if (client.Room == null || !client.IsConnected.Value) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index cbba4babe5..ae8c3113ff 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -2,9 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.ExceptionExtensions; @@ -21,13 +19,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient multiplayerClient { get; set; } - public readonly Bindable TimeBetweenListingPolls = new Bindable(); - public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); private readonly IBindable isConnected = new Bindable(); private readonly Bindable allowPolling = new Bindable(); - private ListingPollingComponent listingPollingComponent; - protected override void LoadComplete() { base.LoadComplete(); @@ -64,19 +58,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (JoinedRoom.Value == null) return; - var joinedRoom = JoinedRoom.Value; - base.PartRoom(); - multiplayerClient.LeaveRoom(); - - // Todo: This is not the way to do this. Basically when we're the only participant and the room closes, there's no way to know if this is actually the case. - // This is delayed one frame because upon exiting the match subscreen, multiplayer updates the polling rate and messes with polling. - Schedule(() => - { - RemoveRoom(joinedRoom); - listingPollingComponent.PollImmediately(); - }); } private void joinMultiplayerRoom(Room room, string password, Action onSuccess = null, Action onError = null) @@ -108,61 +91,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // Don't poll when not connected or when a room has been joined. allowPolling.Value = isConnected.Value && JoinedRoom.Value == null; } - - protected override IEnumerable CreatePollingComponents() => new RoomPollingComponent[] - { - listingPollingComponent = new MultiplayerListingPollingComponent - { - TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls }, - AllowPolling = { BindTarget = allowPolling } - }, - new MultiplayerSelectionPollingComponent - { - TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls }, - AllowPolling = { BindTarget = allowPolling } - } - }; - - private class MultiplayerListingPollingComponent : ListingPollingComponent - { - public readonly IBindable AllowPolling = new Bindable(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - AllowPolling.BindValueChanged(allowPolling => - { - if (!allowPolling.NewValue) - return; - - if (IsLoaded) - PollImmediately(); - }); - } - - protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); - } - - private class MultiplayerSelectionPollingComponent : SelectionPollingComponent - { - public readonly IBindable AllowPolling = new Bindable(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - AllowPolling.BindValueChanged(allowPolling => - { - if (!allowPolling.NewValue) - return; - - if (IsLoaded) - PollImmediately(); - }); - } - - protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); - } } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index c2ad0285b1..cfb19ca3d7 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -13,7 +13,6 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; -using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Overlays; @@ -43,8 +42,6 @@ namespace osu.Game.Screens.OnlinePlay private LoungeSubScreen loungeSubScreen; private ScreenStack screenStack; - private readonly IBindable isIdle = new BindableBool(); - [Cached(Type = typeof(IRoomManager))] protected RoomManager RoomManager { get; private set; } @@ -66,9 +63,6 @@ namespace osu.Game.Screens.OnlinePlay [Resolved] protected IAPIProvider API { get; private set; } - [Resolved(CanBeNull = true)] - private IdleTracker idleTracker { get; set; } - [Resolved(CanBeNull = true)] private OsuLogo logo { get; set; } @@ -151,12 +145,6 @@ namespace osu.Game.Screens.OnlinePlay apiState.BindTo(API.State); apiState.BindValueChanged(onlineStateChanged, true); - - if (idleTracker != null) - { - isIdle.BindTo(idleTracker.IsIdle); - isIdle.BindValueChanged(idle => UpdatePollingRate(idle.NewValue), true); - } } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) @@ -166,8 +154,6 @@ namespace osu.Game.Screens.OnlinePlay return dependencies; } - protected abstract void UpdatePollingRate(bool isIdle); - private void forcefullyExit() { // This is temporary since we don't currently have a way to force screens to be exited @@ -203,8 +189,6 @@ namespace osu.Game.Screens.OnlinePlay screenStack.CurrentScreen.OnResuming(last); base.OnResuming(last); - - UpdatePollingRate(isIdle.Value); } public override void OnSuspending(IScreen next) @@ -214,8 +198,6 @@ namespace osu.Game.Screens.OnlinePlay Debug.Assert(screenStack.CurrentScreen != null); screenStack.CurrentScreen.OnSuspending(next); - - UpdatePollingRate(isIdle.Value); } public override bool OnExiting(IScreen next) @@ -279,15 +261,13 @@ namespace osu.Game.Screens.OnlinePlay if (newScreen is IOsuScreen newOsuScreen) ((IBindable)Activity).BindTo(newOsuScreen.Activity); - - UpdatePollingRate(isIdle.Value); } protected IScreen CurrentSubScreen => screenStack.CurrentScreen; protected abstract string ScreenTitle { get; } - protected abstract RoomManager CreateRoomManager(); + protected virtual RoomManager CreateRoomManager() => new RoomManager(); protected abstract LoungeSubScreen CreateLounge(); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs index 6a78e24ba1..1edeef77df 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/Playlists.cs @@ -1,53 +1,14 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Logging; -using osu.Framework.Screens; -using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; -using osu.Game.Screens.OnlinePlay.Match; namespace osu.Game.Screens.OnlinePlay.Playlists { public class Playlists : OnlinePlayScreen { - protected override void UpdatePollingRate(bool isIdle) - { - var playlistsManager = (PlaylistsRoomManager)RoomManager; - - if (!this.IsCurrentScreen()) - { - playlistsManager.TimeBetweenListingPolls.Value = 0; - playlistsManager.TimeBetweenSelectionPolls.Value = 0; - } - else - { - switch (CurrentSubScreen) - { - case LoungeSubScreen _: - playlistsManager.TimeBetweenListingPolls.Value = isIdle ? 120000 : 15000; - playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 120000 : 15000; - break; - - case RoomSubScreen _: - playlistsManager.TimeBetweenListingPolls.Value = 0; - playlistsManager.TimeBetweenSelectionPolls.Value = isIdle ? 30000 : 5000; - break; - - default: - playlistsManager.TimeBetweenListingPolls.Value = 0; - playlistsManager.TimeBetweenSelectionPolls.Value = 0; - break; - } - } - - Logger.Log($"Polling adjusted (listing: {playlistsManager.TimeBetweenListingPolls.Value}, selection: {playlistsManager.TimeBetweenSelectionPolls.Value})"); - } - protected override string ScreenTitle => "Playlists"; - protected override RoomManager CreateRoomManager() => new PlaylistsRoomManager(); - protected override LoungeSubScreen CreateLounge() => new PlaylistsLoungeSubScreen(); } } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs index eee4d4f407..dced9b8691 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsLoungeSubScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; @@ -66,6 +67,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override RoomSubScreen CreateRoomSubScreen(Room room) => new PlaylistsRoomSubScreen(room); + protected override ListingPollingComponent CreatePollingComponent() => new ListingPollingComponent(); + private enum PlaylistsCategory { Any, diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs deleted file mode 100644 index c55d1c3e94..0000000000 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomManager.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using osu.Framework.Bindables; -using osu.Game.Screens.OnlinePlay.Components; - -namespace osu.Game.Screens.OnlinePlay.Playlists -{ - public class PlaylistsRoomManager : RoomManager - { - public readonly Bindable TimeBetweenListingPolls = new Bindable(); - public readonly Bindable TimeBetweenSelectionPolls = new Bindable(); - - protected override IEnumerable CreatePollingComponents() => new RoomPollingComponent[] - { - new ListingPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenListingPolls } }, - new SelectionPollingComponent { TimeBetweenPolls = { BindTarget = TimeBetweenSelectionPolls } } - }; - } -} diff --git a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs index d37a64fa4b..2e9c0d1d53 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs @@ -33,10 +33,10 @@ namespace osu.Game.Tests.Visual.OnlinePlay room.RoomID.Value ??= Rooms.Select(r => r.RoomID.Value).Where(id => id != null).Select(id => id.Value).DefaultIfEmpty().Max() + 1; onSuccess?.Invoke(room); - AddRoom(room); + AddOrUpdateRoom(room); } - public void AddRoom(Room room) + public void AddOrUpdateRoom(Room room) { Rooms.Add(room); RoomsUpdated?.Invoke(); @@ -48,6 +48,12 @@ namespace osu.Game.Tests.Visual.OnlinePlay RoomsUpdated?.Invoke(); } + public void ClearRooms() + { + Rooms.Clear(); + RoomsUpdated?.Invoke(); + } + public void JoinRoom(Room room, string password, Action onSuccess = null, Action onError = null) { JoinRoomRequested?.Invoke(room, password); From 7cbf4c48edc94af45f10468eb34ca24565d55e28 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 17:59:18 +0900 Subject: [PATCH 259/961] Fix multiplayer polling when not connected --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 15 ++++---- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 37 ++++++++++++++----- .../Multiplayer/MultiplayerRoomManager.cs | 22 ----------- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 50f7baa44c..4525599a52 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -44,8 +44,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge AutoSizeAxes = Axes.Both }; - protected ListingPollingComponent ListingPollingComponent { get; private set; } - [Resolved] private Bindable selectedRoom { get; set; } @@ -73,6 +71,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private RoomsContainer roomsContainer; private SearchTextBox searchTextBox; private Dropdown statusDropdown; + private ListingPollingComponent listingPollingComponent; [BackgroundDependencyLoader] private void load() @@ -83,7 +82,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { - ListingPollingComponent = CreatePollingComponent(), + listingPollingComponent = CreatePollingComponent(), new Container { RelativeSizeAxes = Axes.Both, @@ -183,7 +182,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced()); ruleset.BindValueChanged(_ => UpdateFilter()); - ListingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); + listingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); if (idleTracker != null) { @@ -331,7 +330,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void updateLoadingLayer() { - if (operationInProgress.Value || !ListingPollingComponent.HasPolledOnce.Value) + if (operationInProgress.Value || !listingPollingComponent.HasPolledOnce.Value) loadingLayer.Show(); else loadingLayer.Hide(); @@ -340,11 +339,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void updatePollingRate() { if (!this.IsCurrentScreen()) - ListingPollingComponent.TimeBetweenPolls.Value = 0; + listingPollingComponent.TimeBetweenPolls.Value = 0; else - ListingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; + listingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; - Logger.Log($"Polling adjusted (listing: {ListingPollingComponent.TimeBetweenPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {listingPollingComponent.TimeBetweenPolls.Value})"); } protected abstract OsuButton CreateNewRoomButton(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index db6096e93b..3f20202ec7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -25,10 +25,23 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } + private MultiplayerListingPollingComponent listingPollingComponent; + + private readonly IBindable isConnected = new Bindable(); + private readonly Bindable allowPolling = new Bindable(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + isConnected.BindTo(client.IsConnected); + isConnected.BindValueChanged(c => Scheduler.AddOnce(() => listingPollingComponent.AllowPolling = c.NewValue)); + } + public override void OnResuming(IScreen last) { base.OnResuming(last); - ListingPollingComponent.PollImmediately(); + listingPollingComponent.PollImmediately(); } protected override FilterCriteria CreateFilterCriteria() @@ -49,7 +62,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); - protected override ListingPollingComponent CreatePollingComponent() => new MultiplayerListingPollingComponent(); + protected override ListingPollingComponent CreatePollingComponent() => listingPollingComponent = new MultiplayerListingPollingComponent(); protected override void OpenNewRoom(Room room) { @@ -64,23 +77,27 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private class MultiplayerListingPollingComponent : ListingPollingComponent { - public readonly IBindable AllowPolling = new Bindable(); + private bool allowPolling; - protected override void LoadComplete() + public bool AllowPolling { - base.LoadComplete(); - - AllowPolling.BindValueChanged(allowPolling => + get => allowPolling; + set { - if (!allowPolling.NewValue) + if (allowPolling == value) + return; + + allowPolling = value; + + if (!allowPolling) return; if (IsLoaded) PollImmediately(); - }); + } } - protected override Task Poll() => !AllowPolling.Value ? Task.CompletedTask : base.Poll(); + protected override Task Poll() => !AllowPolling ? Task.CompletedTask : base.Poll(); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index ae8c3113ff..2d94b2328d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -4,7 +4,6 @@ using System; using System.Diagnostics; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.ExceptionExtensions; using osu.Framework.Logging; using osu.Game.Online.Multiplayer; @@ -19,18 +18,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient multiplayerClient { get; set; } - private readonly IBindable isConnected = new Bindable(); - private readonly Bindable allowPolling = new Bindable(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - isConnected.BindTo(multiplayerClient.IsConnected); - isConnected.BindValueChanged(_ => Scheduler.AddOnce(updatePolling)); - JoinedRoom.BindValueChanged(_ => Scheduler.AddOnce(updatePolling), true); - } - public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) => base.CreateRoom(room, r => joinMultiplayerRoom(r, r.Password.Value, onSuccess, onError), onError); @@ -82,14 +69,5 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } }); } - - private void updatePolling() - { - if (!isConnected.Value) - ClearRooms(); - - // Don't poll when not connected or when a room has been joined. - allowPolling.Value = isConnected.Value && JoinedRoom.Value == null; - } } } From 83935540caf400882750283724326934c556110b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:11:52 +0900 Subject: [PATCH 260/961] Add selection polling component to PlaylistsRoomSubScreen --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 16 +++++-------- .../Playlists/PlaylistsRoomSubScreen.cs | 24 +++++++++++++++---- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 4525599a52..06db462205 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -59,9 +59,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [Resolved] private IBindable ruleset { get; set; } - [Resolved(CanBeNull = true)] - private IdleTracker idleTracker { get; set; } - [CanBeNull] private IDisposable joiningRoomOperation { get; set; } @@ -73,9 +70,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private Dropdown statusDropdown; private ListingPollingComponent listingPollingComponent; - [BackgroundDependencyLoader] - private void load() + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] IdleTracker idleTracker) { + if (idleTracker != null) + isIdle.BindTo(idleTracker.IsIdle); + filter ??= new Bindable(new FilterCriteria()); OsuScrollContainer scrollContainer; @@ -184,11 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge listingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); - if (idleTracker != null) - { - isIdle.BindTo(idleTracker.IsIdle); - isIdle.BindValueChanged(_ => updatePollingRate(), true); - } + isIdle.BindValueChanged(_ => updatePollingRate(), true); if (ongoingOperationTracker != null) { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 953c687087..682b055766 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -3,11 +3,14 @@ using System.Diagnostics; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; @@ -33,12 +36,13 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved(typeof(Room), nameof(Room.Playlist))] private BindableList playlist { get; set; } + private readonly IBindable isIdle = new BindableBool(); + private MatchSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; - private OverlinedHeader participantsHeader; - private GridContainer mainContent; + private SelectionPollingComponent selectionPollingComponent; public PlaylistsRoomSubScreen(Room room) { @@ -46,11 +50,15 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Activity.Value = new UserActivity.InLobby(room); } - [BackgroundDependencyLoader] - private void load() + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] IdleTracker idleTracker) { + if (idleTracker != null) + isIdle.BindTo(idleTracker.IsIdle); + AddRangeInternal(new Drawable[] { + selectionPollingComponent = new SelectionPollingComponent(), mainContent = new GridContainer { RelativeSizeAxes = Axes.Both, @@ -260,6 +268,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { base.LoadComplete(); + isIdle.BindValueChanged(_ => updatePollingRate(), true); + roomId.BindValueChanged(id => { if (id.NewValue == null) @@ -275,6 +285,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, true); } + private void updatePollingRate() + { + selectionPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 30000 : 5000; + Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})"); + } + protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value) { Exited = () => leaderboard.RefreshScores() From f5cea0cacd34535f58b43c216f03ed60b1bb31ec Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 12:12:20 +0300 Subject: [PATCH 261/961] Fix failing test and rename to match new behaviour --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index a9004987df..080a1502b0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -84,7 +84,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestSpectatorPlayerSettingsHidden() + public void TestSpectatorPlayerInteractiveElementsHidden() { start(new[] { PLAYER_1_ID, PLAYER_2_ID }); loadSpectateScreen(false); @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && - !p.ChildrenOfType().Single().ShowHandle)); + p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false)); } [Test] From 6a46105b5efe9b6a2fcaa95838f53d1793daeb90 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:12:32 +0900 Subject: [PATCH 262/961] Fix incorrect dependency --- osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs index 95b4c4284c..cd224a7347 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomPollingComponent.cs @@ -13,6 +13,6 @@ namespace osu.Game.Screens.OnlinePlay.Components protected IAPIProvider API { get; private set; } [Resolved] - protected IRoomManager RoomManager { get; set; } + protected IRoomManager RoomManager { get; private set; } } } From 1bae7173d3794d1cecca63fb31fecbc4a64ef3f9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:13:55 +0900 Subject: [PATCH 263/961] Fix initial multiplayer poll --- .../OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 3f20202ec7..d36462f482 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -28,7 +28,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private MultiplayerListingPollingComponent listingPollingComponent; private readonly IBindable isConnected = new Bindable(); - private readonly Bindable allowPolling = new Bindable(); protected override void LoadComplete() { @@ -36,6 +35,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer isConnected.BindTo(client.IsConnected); isConnected.BindValueChanged(c => Scheduler.AddOnce(() => listingPollingComponent.AllowPolling = c.NewValue)); + listingPollingComponent.AllowPolling = isConnected.Value; } public override void OnResuming(IScreen last) From d527eb3d8b8f89bafa8870fe691f3ef6127fca67 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Fri, 13 Aug 2021 17:15:18 +0800 Subject: [PATCH 264/961] Apply suggestions from code review Co-authored-by: Dean Herbert --- osu.Game/Localisation/GameplaySettingsStrings.cs | 6 +++--- osu.Game/Localisation/GeneralSettingsStrings.cs | 2 +- .../Overlays/Settings/Sections/Gameplay/GeneralSettings.cs | 6 +++--- .../Overlays/Settings/Sections/General/LanguageSettings.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 4354272ab5..c63fa5ddcc 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -22,12 +22,12 @@ namespace osu.Game.Localisation /// /// "Background dim" /// - public static LocalisableString Dim => new TranslatableString(getKey(@"dim"), @"Background dim"); + public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"dim"), @"Background dim"); /// /// "Background blur" /// - public static LocalisableString Blur => new TranslatableString(getKey(@"blur"), @"Background blur"); + public static LocalisableString BackgroundBlur => new TranslatableString(getKey(@"blur"), @"Background blur"); /// /// "Lighten playfield during breaks" @@ -57,7 +57,7 @@ namespace osu.Game.Localisation /// /// "Always show key overlay" /// - public static LocalisableString KeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay"); + public static LocalisableString AlwaysShowKeyOverlay => new TranslatableString(getKey(@"key_overlay"), @"Always show key overlay"); /// /// "Positional hitsounds" diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index 19fb8de972..a60e4891f4 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -27,7 +27,7 @@ namespace osu.Game.Localisation /// /// "Prefer metadata in original language" /// - public static LocalisableString PreferOriginal => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language"); + public static LocalisableString PreferOriginalMetadataLanguage => new TranslatableString(getKey(@"prefer_original"), @"Prefer metadata in original language"); /// /// "Updates" diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index efb586fdca..04332fcdd3 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -22,14 +22,14 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay { new SettingsSlider { - LabelText = GameplaySettingsStrings.Dim, + LabelText = GameplaySettingsStrings.BackgroundDim, Current = config.GetBindable(OsuSetting.DimLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true }, new SettingsSlider { - LabelText = GameplaySettingsStrings.Blur, + LabelText = GameplaySettingsStrings.BackgroundBlur, Current = config.GetBindable(OsuSetting.BlurLevel), KeyboardStep = 0.01f, DisplayAsPercentage = true @@ -62,7 +62,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay }, new SettingsCheckbox { - LabelText = GameplaySettingsStrings.KeyOverlay, + LabelText = GameplaySettingsStrings.AlwaysShowKeyOverlay, Current = config.GetBindable(OsuSetting.KeyOverlay) }, new SettingsCheckbox diff --git a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs index ac95a713bf..200618c469 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LanguageSettings.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Settings.Sections.General }, new SettingsCheckbox { - LabelText = GeneralSettingsStrings.PreferOriginal, + LabelText = GeneralSettingsStrings.PreferOriginalMetadataLanguage, Current = frameworkConfig.GetBindable(FrameworkSetting.ShowUnicode) }, }; From 1f992e67f3b29f63a0f965eb6c4e3ed26a6699c8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:17:18 +0900 Subject: [PATCH 265/961] Fix listing polling rate when entering room --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 06db462205..abe06bae9e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge listingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); - isIdle.BindValueChanged(_ => updatePollingRate(), true); + isIdle.BindValueChanged(_ => updatePollingRate(this.IsCurrentScreen()), true); if (ongoingOperationTracker != null) { @@ -272,13 +272,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void onReturning() { - updatePollingRate(); + updatePollingRate(true); searchTextBox.HoldFocus = true; } private void onLeaving() { - updatePollingRate(); + updatePollingRate(false); searchTextBox.HoldFocus = false; // ensure any password prompt is dismissed. @@ -332,9 +332,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge loadingLayer.Hide(); } - private void updatePollingRate() + private void updatePollingRate(bool isCurrentScreen) { - if (!this.IsCurrentScreen()) + if (!isCurrentScreen) listingPollingComponent.TimeBetweenPolls.Value = 0; else listingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; From c71a581106f1640a4303ead14755820cfc1c29d7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:24:19 +0900 Subject: [PATCH 266/961] Fix exception when leaving match --- .../OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs | 9 ++++++++- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index d36462f482..0756c78211 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -41,7 +41,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override void OnResuming(IScreen last) { base.OnResuming(last); - listingPollingComponent.PollImmediately(); + + // Upon having left a room, we don't know whether we were the only participant, and whether the room is now closed as a result of leaving it. + // To work around this, temporarily clear all rooms until the next listing poll. + if (last is MultiplayerMatchSubScreen match) + { + RoomManager.RemoveRoom(match.Room); + listingPollingComponent.PollImmediately(); + } } protected override FilterCriteria CreateFilterCriteria() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index ec011634b1..72ba4d62fb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -42,6 +42,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override string ShortTitle => "room"; + public readonly Room Room; + [Resolved] private MultiplayerClient client { get; set; } @@ -61,6 +63,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public MultiplayerMatchSubScreen(Room room) { + Room = room; + Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); } @@ -323,10 +327,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override bool OnExiting(IScreen next) { - // We don't know whether we're the only participant in the room, and whether the room will close after we leave it as a result. - // To work around this, temporarily remove the room until the next listing poll retrieves it. - RoomManager?.RemoveRoom(currentRoom.Value); - // the room may not be left immediately after a disconnection due to async flow, // so checking the IsConnected status is also required. if (client.Room == null || !client.IsConnected.Value) From fbadc4897e211db035eb495d19cc797535e4fbc1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 18:28:20 +0900 Subject: [PATCH 267/961] Remove test scene --- .../TestSceneMultiplayerRoomManager.cs | 157 ------------------ 1 file changed, 157 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs deleted file mode 100644 index 15e9112c47..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerRoomManager.cs +++ /dev/null @@ -1,157 +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 NUnit.Framework; -// using osu.Framework.Testing; -// using osu.Game.Online.Rooms; -// using osu.Game.Screens.OnlinePlay.Components; -// using osu.Game.Tests.Beatmaps; -// using osu.Game.Tests.Visual.OnlinePlay; -// -// namespace osu.Game.Tests.Visual.Multiplayer -// { -// [HeadlessTest] -// public class TestSceneMultiplayerRoomManager : MultiplayerTestScene -// { -// protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies(); -// -// public TestSceneMultiplayerRoomManager() -// : base(false) -// { -// } -// -// [Test] -// public void TestPollsInitially() -// { -// AddStep("create room manager with a few rooms", () => -// { -// RoomManager.CreateRoom(createRoom(r => r.Name.Value = "1")); -// RoomManager.PartRoom(); -// RoomManager.CreateRoom(createRoom(r => r.Name.Value = "2")); -// RoomManager.PartRoom(); -// RoomManager.ClearRooms(); -// }); -// -// AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); -// AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); -// } -// -// [Test] -// public void TestRoomsClearedOnDisconnection() -// { -// AddStep("create room manager with a few rooms", () => -// { -// RoomManager.CreateRoom(createRoom()); -// RoomManager.PartRoom(); -// RoomManager.CreateRoom(createRoom()); -// RoomManager.PartRoom(); -// }); -// -// AddStep("disconnect", () => Client.Disconnect()); -// -// AddAssert("rooms cleared", () => ((RoomManager)RoomManager).Rooms.Count == 0); -// AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); -// } -// -// [Test] -// public void TestRoomsPolledOnReconnect() -// { -// AddStep("create room manager with a few rooms", () => -// { -// RoomManager.CreateRoom(createRoom()); -// RoomManager.PartRoom(); -// RoomManager.CreateRoom(createRoom()); -// RoomManager.PartRoom(); -// }); -// -// AddStep("disconnect", () => Client.Disconnect()); -// AddStep("connect", () => Client.Connect()); -// -// AddAssert("manager polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 2); -// AddAssert("initial rooms received", () => RoomManager.InitialRoomsReceived.Value); -// } -// -// [Test] -// public void TestRoomsNotPolledWhenJoined() -// { -// AddStep("create room manager with a room", () => -// { -// RoomManager.CreateRoom(createRoom()); -// RoomManager.ClearRooms(); -// }); -// -// AddAssert("manager not polled for rooms", () => ((RoomManager)RoomManager).Rooms.Count == 0); -// AddAssert("initial rooms not received", () => !RoomManager.InitialRoomsReceived.Value); -// } -// -// [Test] -// public void TestMultiplayerRoomJoinedWhenCreated() -// { -// AddStep("create room manager with a room", () => -// { -// RoomManager.CreateRoom(createRoom()); -// }); -// -// AddUntilStep("multiplayer room joined", () => Client.Room != null); -// } -// -// [Test] -// public void TestMultiplayerRoomPartedWhenAPIRoomParted() -// { -// AddStep("create room manager with a room", () => -// { -// RoomManager.CreateRoom(createRoom()); -// RoomManager.PartRoom(); -// }); -// -// AddAssert("multiplayer room parted", () => Client.Room == null); -// } -// -// [Test] -// public void TestMultiplayerRoomJoinedWhenAPIRoomJoined() -// { -// AddStep("create room manager with a room", () => -// { -// var r = createRoom(); -// RoomManager.CreateRoom(r); -// RoomManager.PartRoom(); -// RoomManager.JoinRoom(r); -// }); -// -// AddUntilStep("multiplayer room joined", () => Client.Room != null); -// } -// -// private Room createRoom(Action initFunc = null) -// { -// var room = new Room -// { -// Name = -// { -// Value = "test room" -// }, -// Playlist = -// { -// new PlaylistItem -// { -// Beatmap = { Value = new TestBeatmap(Ruleset.Value).BeatmapInfo }, -// Ruleset = { Value = Ruleset.Value } -// } -// } -// }; -// -// initFunc?.Invoke(room); -// return room; -// } -// -// private class TestDependencies : MultiplayerTestSceneDependencies -// { -// public TestDependencies() -// { -// // Need to set these values as early as possible. -// RoomManager.TimeBetweenListingPolls.Value = 1; -// RoomManager.TimeBetweenSelectionPolls.Value = 1; -// } -// } -// } -// } From 7cf6b551d353ffd8393b3ed4d7489f5c6d23bca3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 13:01:17 +0300 Subject: [PATCH 268/961] Replace until step with wait step with explanatory comment --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 080a1502b0..62a9b597ad 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -93,10 +93,15 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("all player loader settings hidden", () => this.ChildrenOfType().All(l => !l.ChildrenOfType>().Any())); AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded); - AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => + + // components wrapped in skinnable target containers load asynchronously, potentially taking more than one frame to load. + // wait once to properly execute the assert. + AddWaitStep("wait for async load", 1); + + AddAssert("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && - p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false)); + !p.ChildrenOfType().Single().ShowHandle)); } [Test] From e3f91413cf0397c68c37b043a10fe5a04a2e89fe Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 13:23:34 +0700 Subject: [PATCH 269/961] add pinned comment test case for comment container --- .../Online/TestSceneCommentsContainer.cs | 106 ++++++++++++------ 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index cd22bb2513..3ad3474fc0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -42,19 +42,21 @@ namespace osu.Game.Tests.Visual.Online () => commentsContainer.ChildrenOfType().Single().IsLoading); } - [Test] - public void TestSingleCommentsPage() + [TestCase(false)] + [TestCase(true)] + public void TestSingleCommentsPage(bool withPinned) { - setUpCommentsResponse(exampleComments); + setUpCommentsResponse(getExampleComments(withPinned)); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); AddUntilStep("show more button hidden", () => commentsContainer.ChildrenOfType().Single().Alpha == 0); } - [Test] - public void TestMultipleCommentPages() + [TestCase(false)] + [TestCase(true)] + public void TestMultipleCommentPages(bool withPinned) { - var comments = exampleComments; + var comments = getExampleComments(withPinned); comments.HasMore = true; comments.TopLevelCount = 10; @@ -64,11 +66,12 @@ namespace osu.Game.Tests.Visual.Online () => commentsContainer.ChildrenOfType().Single().Alpha == 1); } - [Test] - public void TestMultipleLoads() + [TestCase(false)] + [TestCase(true)] + public void TestMultipleLoads(bool withPinned) { - var comments = exampleComments; - int topLevelCommentCount = exampleComments.Comments.Count; + var comments = getExampleComments(withPinned); + int topLevelCommentCount = comments.Comments.Count; AddStep("hide container", () => commentsContainer.Hide()); setUpCommentsResponse(comments); @@ -92,38 +95,71 @@ namespace osu.Game.Tests.Visual.Online }; }); - private CommentBundle exampleComments => new CommentBundle + private CommentBundle getExampleComments(bool withPinned = false) { - Comments = new List + var bundle = new CommentBundle { - new Comment + Comments = new List { - Id = 1, - Message = "This is a comment", - LegacyName = "FirstUser", - CreatedAt = DateTimeOffset.Now, - VotesCount = 19, - RepliesCount = 1 + new Comment + { + Id = 1, + Message = "This is a comment", + LegacyName = "FirstUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 19, + RepliesCount = 1 + }, + new Comment + { + Id = 5, + ParentId = 1, + Message = "This is a child comment", + LegacyName = "SecondUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 4, + }, + new Comment + { + Id = 10, + Message = "This is another comment", + LegacyName = "ThirdUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 0 + }, }, - new Comment + IncludedComments = new List(), + PinnedComments = new List(), + }; + + if (withPinned) + { + var pinnedComment = new Comment { - Id = 5, - ParentId = 1, - Message = "This is a child comment", - LegacyName = "SecondUser", + Id = 15, + Message = "This is pinned comment", + LegacyName = "PinnedUser", CreatedAt = DateTimeOffset.Now, - VotesCount = 4, - }, - new Comment + VotesCount = 999, + Pinned = true, + RepliesCount = 1, + }; + + bundle.Comments.Add(pinnedComment); + bundle.PinnedComments.Add(pinnedComment); + + bundle.Comments.Add(new Comment { - Id = 10, - Message = "This is another comment", - LegacyName = "ThirdUser", + Id = 20, + Message = "Reply to pinned comment", + LegacyName = "AbandonedUser", CreatedAt = DateTimeOffset.Now, - VotesCount = 0 - }, - }, - IncludedComments = new List(), - }; + VotesCount = 0, + ParentId = 15, + }); + } + + return bundle; + } } } From c32ba9e38fe45f6200c8305fcc0938046cb792e6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 15:06:11 +0300 Subject: [PATCH 270/961] Remove arbitrarily-set wait step with until step instead, keeping the comment --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 62a9b597ad..f1ddfefe33 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -95,10 +95,8 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for players to load", () => spectatorScreen.AllPlayersLoaded); // components wrapped in skinnable target containers load asynchronously, potentially taking more than one frame to load. - // wait once to properly execute the assert. - AddWaitStep("wait for async load", 1); - - AddAssert("all interactive elements removed", () => this.ChildrenOfType().All(p => + // therefore use until step rather than direct assert to account for that. + AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && !p.ChildrenOfType().Single().ShowHandle)); From 1fed9193f86c4052393c1a58ea09c0f8c2756272 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 13 Aug 2021 15:24:10 +0300 Subject: [PATCH 271/961] Revert reverted segment to fix failure --- .../Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index f1ddfefe33..9bb9c24c6b 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("all interactive elements removed", () => this.ChildrenOfType().All(p => !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && - !p.ChildrenOfType().Single().ShowHandle)); + p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false)); } [Test] From 480d5ffa5d1370539f10c69ca3a05450e8a7a5ad Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 19:22:46 +0700 Subject: [PATCH 272/961] add pinned comment to users setter in comment bundle --- .../API/Requests/Responses/CommentBundle.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs index 0585d75f0c..4070df493d 100644 --- a/osu.Game/Online/API/Requests/Responses/CommentBundle.cs +++ b/osu.Game/Online/API/Requests/Responses/CommentBundle.cs @@ -4,6 +4,7 @@ using Newtonsoft.Json; using osu.Game.Users; using System.Collections.Generic; +using System.Linq; namespace osu.Game.Online.API.Requests.Responses { @@ -52,26 +53,17 @@ namespace osu.Game.Online.API.Requests.Responses { users = value; - value.ForEach(u => + foreach (var user in value) { - Comments.ForEach(c => + foreach (var comment in Comments.Concat(IncludedComments).Concat(PinnedComments)) { - if (c.UserId == u.Id) - c.User = u; + if (comment.UserId == user.Id) + comment.User = user; - if (c.EditedById == u.Id) - c.EditedUser = u; - }); - - IncludedComments.ForEach(c => - { - if (c.UserId == u.Id) - c.User = u; - - if (c.EditedById == u.Id) - c.EditedUser = u; - }); - }); + if (comment.EditedById == user.Id) + comment.EditedUser = user; + } + } } } From cf0e9a1eec242658bddb152bd47ae51adc3e29d5 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 19:01:52 +0700 Subject: [PATCH 273/961] add pinned content section --- .../Overlays/Comments/CommentsContainer.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index fe8d6f0178..9abae63f93 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -38,6 +38,7 @@ namespace osu.Game.Overlays.Comments private CancellationTokenSource loadCancellation; private int currentPage; + private FillFlowContainer pinnedContent; private FillFlowContainer content; private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; @@ -63,6 +64,25 @@ namespace osu.Game.Overlays.Comments Children = new Drawable[] { commentCounter = new TotalCommentsCounter(), + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background4, + }, + pinnedContent = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }, + }, + }, new CommentsHeader { Sort = { BindTarget = Sort }, @@ -173,6 +193,7 @@ namespace osu.Game.Overlays.Comments deletedCommentsCounter.Count.Value = 0; moreButton.Show(); moreButton.IsLoading = true; + pinnedContent.Clear(); content.Clear(); CommentDictionary.Clear(); } @@ -202,7 +223,7 @@ namespace osu.Game.Overlays.Comments var topLevelComments = new List(); var orphaned = new List(); - foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments)) + foreach (var comment in bundle.Comments.Concat(bundle.IncludedComments).Concat(bundle.PinnedComments)) { // Exclude possible duplicated comments. if (CommentDictionary.ContainsKey(comment.Id)) @@ -219,13 +240,15 @@ namespace osu.Game.Overlays.Comments { LoadComponentsAsync(topLevelComments, loaded => { - content.AddRange(loaded); + pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned)); + content.AddRange(loaded.Where(d => !d.Comment.Pinned)); deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel); if (bundle.HasMore) { int loadedTopLevelComments = 0; + pinnedContent.Children.OfType().ForEach(p => loadedTopLevelComments++); content.Children.OfType().ForEach(p => loadedTopLevelComments++); moreButton.Current.Value = bundle.TopLevelCount - loadedTopLevelComments; From 1fcb1cdb108fb4049a8aa3f0d0de78408e50e187 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 22:01:47 +0900 Subject: [PATCH 274/961] Add todo --- osu.Game/Online/Rooms/Room.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Rooms/Room.cs b/osu.Game/Online/Rooms/Room.cs index 364336783d..d964060f10 100644 --- a/osu.Game/Online/Rooms/Room.cs +++ b/osu.Game/Online/Rooms/Room.cs @@ -134,7 +134,7 @@ namespace osu.Game.Online.Rooms /// The position of this in the list. This is not read from or written to the API. /// [JsonIgnore] - public readonly Bindable Position = new Bindable(-1); + public readonly Bindable Position = new Bindable(-1); // Todo: This does not need to exist. public Room() { From 155e9e16a5d08d2bcb52dfaeda81af6903e478f2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 22:08:34 +0900 Subject: [PATCH 275/961] Refactorings --- osu.Game/Screens/OnlinePlay/IRoomManager.cs | 12 ++++++++++++ .../Multiplayer/MultiplayerLoungeSubScreen.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/IRoomManager.cs b/osu.Game/Screens/OnlinePlay/IRoomManager.cs index baf84e25f9..6e1ffbda74 100644 --- a/osu.Game/Screens/OnlinePlay/IRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/IRoomManager.cs @@ -23,10 +23,22 @@ namespace osu.Game.Screens.OnlinePlay /// IBindableList Rooms { get; } + /// + /// Adds a to this . + /// If already existing, the local room will be updated with the given one. + /// + /// The incoming . void AddOrUpdateRoom(Room room); + /// + /// Removes a from this . + /// + /// The to remove. void RemoveRoom(Room room); + /// + /// Removes all s from this . + /// void ClearRooms(); /// diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 0756c78211..77db955f0a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -43,7 +43,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.OnResuming(last); // Upon having left a room, we don't know whether we were the only participant, and whether the room is now closed as a result of leaving it. - // To work around this, temporarily clear all rooms until the next listing poll. + // To work around this, temporarily remove the room and trigger an immediate listing poll. if (last is MultiplayerMatchSubScreen match) { RoomManager.RemoveRoom(match.Room); From 0e66a0596340722b6175438a28f3682825b38d46 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 13 Aug 2021 22:29:22 +0900 Subject: [PATCH 276/961] Hide left border of beatmap wedge --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 3 ++- osu.Game/Screens/Select/SongSelect.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 3779523094..5b4e077100 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -35,6 +35,7 @@ namespace osu.Game.Screens.Select { public class BeatmapInfoWedge : VisibilityContainer { + public const float BORDER_THICKNESS = 2.5f; private const float shear_width = 36.75f; private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0); @@ -59,7 +60,7 @@ namespace osu.Game.Screens.Select Shear = wedged_container_shear; Masking = true; BorderColour = new Color4(221, 255, 255, 255); - BorderThickness = 2.5f; + BorderThickness = BORDER_THICKNESS; Alpha = 0; EdgeEffect = new EdgeEffectParameters { diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0e113a71bc..bb3df0d4e0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -203,6 +203,7 @@ namespace osu.Game.Screens.Select Margin = new MarginPadding { Right = left_area_padding, + Left = -BeatmapInfoWedge.BORDER_THICKNESS, // Hide the left border }, }, new Container From 6d726bf0465233ba78665fa3a5a888eeca833301 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 22:54:41 +0700 Subject: [PATCH 277/961] Change spacing Co-authored-by: Salman Ahmed --- 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 389e61bc30..9937623418 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Comments { AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, - Spacing = new Vector2(3, 0), + Spacing = new Vector2(2, 0), Alpha = Comment.Pinned ? 1 : 0, Children = new Drawable[] { From 1c32993fe51c56876ce0797d8a5151af471b87c3 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 23:03:42 +0700 Subject: [PATCH 278/961] initialize pinned comments in test offline comment --- .../Visual/Online/TestSceneOfflineCommentsContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs index 628ae0971b..4f7947b69c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOfflineCommentsContainer.cs @@ -149,6 +149,7 @@ namespace osu.Game.Tests.Visual.Online } }, IncludedComments = new List(), + PinnedComments = new List(), UserVotes = new List { 5 @@ -178,6 +179,7 @@ namespace osu.Game.Tests.Visual.Online }, }, IncludedComments = new List(), + PinnedComments = new List(), }; private class TestCommentsContainer : CommentsContainer From 48b84db7b978337329083af3c7e9fdd73012c318 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 13 Aug 2021 23:48:14 +0700 Subject: [PATCH 279/961] add no comment and single comment test --- .../Online/TestSceneCommentsContainer.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 3ad3474fc0..4809a737d9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -82,6 +82,48 @@ namespace osu.Game.Tests.Visual.Online () => commentsContainer.ChildrenOfType().Count() == topLevelCommentCount); } + [Test] + public void TestNoComment() + { + var comments = getExampleComments(); + comments.Comments.Clear(); + + setUpCommentsResponse(comments); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + AddAssert("no comment showed", () => !commentsContainer.ChildrenOfType().Any()); + } + + [TestCase(false)] + [TestCase(true)] + public void TestSingleComment(bool withPinned) + { + var comment = new Comment + { + Id = 1, + Message = "This is a single comment", + LegacyName = "SingleUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 0, + Pinned = withPinned, + }; + + var bundle = new CommentBundle + { + Comments = new List { comment }, + IncludedComments = new List(), + PinnedComments = new List(), + }; + + if (withPinned) + bundle.PinnedComments.Add(comment); + + setUpCommentsResponse(bundle); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + AddUntilStep("wait comment load", () => commentsContainer.ChildrenOfType().Any()); + AddAssert("only one comment showed", () => + commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); + } + private void setUpCommentsResponse(CommentBundle commentBundle) => AddStep("set up response", () => { From a710bbf6aec07f404d149a686552694b54aa227e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 14 Aug 2021 00:03:05 +0700 Subject: [PATCH 280/961] remove background colour for no comment placeholder --- osu.Game/Overlays/Comments/CommentsContainer.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 9abae63f93..6b3d816e84 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -323,11 +323,6 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X; AddRangeInternal(new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background4 - }, new OsuSpriteText { Anchor = Anchor.CentreLeft, From 4494ff55e325f96227e8c278d4ac4d759edc1833 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 14 Aug 2021 00:17:45 +0700 Subject: [PATCH 281/961] fix pinned drawable comment test --- osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs index 5d1f3affc6..b26850feb2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDrawableComment.cs @@ -43,9 +43,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep(description, () => { - if (description == "Pinned") - comment.Pinned = true; - + comment.Pinned = description == "Pinned"; comment.Message = text; container.Add(new DrawableComment(comment)); }); From 9233f396aa0787ce9843fe3fcfad3dfe6dd8760b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 14 Aug 2021 00:22:01 +0700 Subject: [PATCH 282/961] centered thumbtack icon and text --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 9937623418..d80d566f3a 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -156,11 +156,15 @@ namespace osu.Game.Overlays.Comments { Icon = FontAwesome.Solid.Thumbtack, Size = new Vector2(14), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, }, new OsuSpriteText { Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), Text = CommentsStrings.Pinned, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, } }, }, From 2e9ab78275353624a45fcfcb58347f160fdeea42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 13 Aug 2021 21:30:26 +0200 Subject: [PATCH 283/961] Split test scene into two to follow class split --- .../TestSceneMultiplayerResults.cs | 51 +++++++++++++++++++ .../TestSceneMultiplayerTeamResults.cs | 37 +------------- 2 files changed, 52 insertions(+), 36 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs new file mode 100644 index 0000000000..ff06d4d9c7 --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerResults.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Osu; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMultiplayerResults : ScreenTestScene + { + [Test] + public void TestDisplayResults() + { + MultiplayerResultsScreen screen = null; + + AddStep("show results screen", () => + { + var rulesetInfo = new OsuRuleset().RulesetInfo; + var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo; + + var score = new ScoreInfo + { + Rank = ScoreRank.B, + TotalScore = 987654, + Accuracy = 0.8, + MaxCombo = 500, + Combo = 250, + Beatmap = beatmapInfo, + User = new User { Username = "Test user" }, + Date = DateTimeOffset.Now, + OnlineScoreID = 12345, + Ruleset = rulesetInfo, + }; + + PlaylistItem playlistItem = new PlaylistItem + { + BeatmapID = beatmapInfo.ID, + }; + + Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem)); + }); + + AddUntilStep("wait for loaded", () => screen.IsLoaded); + } + } +} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs index a21996383f..0a8bda7ec0 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerTeamResults.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [TestCase(7483253, 1048576)] [TestCase(1048576, 7483253)] [TestCase(1048576, 1048576)] - public void TestDisplayWithTeams(int team1Score, int team2Score) + public void TestDisplayTeamResults(int team1Score, int team2Score) { MultiplayerResultsScreen screen = null; @@ -57,40 +57,5 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for loaded", () => screen.IsLoaded); } - - [Test] - public void TestDisplayWithoutTeams() - { - MultiplayerResultsScreen screen = null; - - AddStep("show results screen", () => - { - var rulesetInfo = new OsuRuleset().RulesetInfo; - var beatmapInfo = CreateBeatmap(rulesetInfo).BeatmapInfo; - - var score = new ScoreInfo - { - Rank = ScoreRank.B, - TotalScore = 987654, - Accuracy = 0.8, - MaxCombo = 500, - Combo = 250, - Beatmap = beatmapInfo, - User = new User { Username = "Test user" }, - Date = DateTimeOffset.Now, - OnlineScoreID = 12345, - Ruleset = rulesetInfo, - }; - - PlaylistItem playlistItem = new PlaylistItem - { - BeatmapID = beatmapInfo.ID, - }; - - Stack.Push(screen = new MultiplayerResultsScreen(score, 1, playlistItem)); - }); - - AddUntilStep("wait for loaded", () => screen.IsLoaded); - } } } From 00317c0e30b4896f5086ec1d202013799e174cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 13 Aug 2021 23:44:07 +0200 Subject: [PATCH 284/961] Round when totalling up team scores instead of truncating Matches score handling in `ScoreManager`. --- osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs index 3f9258930e..362ee4a373 100644 --- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.Play.HUD continue; if (TeamScores.TryGetValue(u.Team.Value, out var team)) - team.Value += (int)u.Score.Value; + team.Value += (int)Math.Round(u.Score.Value); } } From e2cc96097f1d53591bb8656bd4da2175b150d76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 13 Aug 2021 23:48:03 +0200 Subject: [PATCH 285/961] Unify match score display formatting Commas are already applied on the multiplayer leaderboard, as well as the results screen. --- osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index 607d08b8ed..68e3f0df7d 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -7,6 +7,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -171,6 +172,8 @@ namespace osu.Game.Screens.Play.HUD => displayedSpriteText.Font = winning ? OsuFont.Torus.With(weight: FontWeight.Bold, size: font_size, fixedWidth: true) : OsuFont.Torus.With(weight: FontWeight.Regular, size: font_size * 0.8f, fixedWidth: true); + + protected override LocalisableString FormatCount(double count) => count.ToLocalisableString(@"N0"); } } } From 5cfb89f18ac02d26168569846255e73703dde9d2 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 14 Aug 2021 10:56:52 +0800 Subject: [PATCH 286/961] Apply suggestions from code review Co-authored-by: Joseph Madamba --- osu.Game/Localisation/UserInterfaceStrings.cs | 2 +- .../Settings/Sections/UserInterface/SongSelectSettings.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index 18a9257732..fcfaf661dc 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -77,7 +77,7 @@ namespace osu.Game.Localisation /// /// "Song Select" /// - public static LocalisableString SoneSelectHeader => new TranslatableString(getKey(@"song_select_header"), @"Song Select"); + public static LocalisableString SongSelectHeader => new TranslatableString(getKey(@"song_select_header"), @"Song Select"); /// /// "Right mouse drag to absolute scroll" diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs index 8596cecbb8..6290046987 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/SongSelectSettings.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface private Bindable minStars; private Bindable maxStars; - protected override LocalisableString Header => UserInterfaceStrings.SoneSelectHeader; + protected override LocalisableString Header => UserInterfaceStrings.SongSelectHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) From e26ccf786e6812a8aca382f061e346f3b5b64a76 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 14 Aug 2021 11:04:38 +0800 Subject: [PATCH 287/961] code style format --- osu.Game/Localisation/OnlineSettingsStrings.cs | 4 ++-- osu.Game/Localisation/SkinSettingsStrings.cs | 2 +- .../Settings/Sections/Online/AlertsAndPrivacySettings.cs | 2 +- osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs | 2 +- osu.Game/Overlays/Settings/Sections/SkinSection.cs | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index 0ef98a720c..0173cc7cbb 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -27,7 +27,7 @@ namespace osu.Game.Localisation /// /// "Show a notification when you receive a private message" /// - public static LocalisableString NotifyOnPM => new TranslatableString(getKey(@"notify_on_pm"), @"Show a notification when you receive a private message"); + public static LocalisableString NotifyOnPrivateMessage => new TranslatableString(getKey(@"notify_on_private_message"), @"Show a notification when you receive a private message"); /// /// "Integrations" @@ -57,7 +57,7 @@ namespace osu.Game.Localisation /// /// "Automatically download beatmaps when spectating" /// - public static LocalisableString AutomaticallyDownload => new TranslatableString(getKey(@"automatically_download"), @"Automatically download beatmaps when spectating"); + public static LocalisableString AutomaticallyDownloadWhenSpectating => new TranslatableString(getKey(@"automatically_download_when_spectating"), @"Automatically download beatmaps when spectating"); /// /// "Show explicit content in search results" diff --git a/osu.Game/Localisation/SkinSettingsStrings.cs b/osu.Game/Localisation/SkinSettingsStrings.cs index 848c01b93a..f22b4d6bf5 100644 --- a/osu.Game/Localisation/SkinSettingsStrings.cs +++ b/osu.Game/Localisation/SkinSettingsStrings.cs @@ -22,7 +22,7 @@ namespace osu.Game.Localisation /// /// "Gameplay cursor size" /// - public static LocalisableString CursorSize => new TranslatableString(getKey(@"cursor_size"), @"Gameplay cursor size"); + public static LocalisableString GameplayCursorSize => new TranslatableString(getKey(@"gameplay_cursor_size"), @"Gameplay cursor size"); /// /// "Adjust gameplay cursor size based on current beatmap" diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 1728b565c2..351a32c72e 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online }, new SettingsCheckbox { - LabelText = OnlineSettingsStrings.NotifyOnPM, + LabelText = OnlineSettingsStrings.NotifyOnPrivateMessage, Current = config.GetBindable(OsuSetting.NotifyOnPrivateMessage) }, }; diff --git a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs index 4200ddda3d..e864260cc6 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/WebSettings.cs @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online }, new SettingsCheckbox { - LabelText = OnlineSettingsStrings.AutomaticallyDownload, + LabelText = OnlineSettingsStrings.AutomaticallyDownloadWhenSpectating, Keywords = new[] { "spectator" }, Current = config.GetBindable(OsuSetting.AutomaticallyDownloadWhenSpectating), }, diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index 007302c584..e0d8252930 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Settings.Sections new ExportSkinButton(), new SettingsSlider { - LabelText = SkinSettingsStrings.CursorSize, + LabelText = SkinSettingsStrings.GameplayCursorSize, Current = config.GetBindable(OsuSetting.GameplayCursorSize), KeyboardStep = 0.01f }, From e6b3aba6e19557e2f2d493fb6d5c57a9c71d3b23 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 14 Aug 2021 14:08:29 +0900 Subject: [PATCH 288/961] Fix incorrectly directed call in `TestMultiplayerClient` --- osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index a28b4140ca..67b79d7390 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -178,7 +178,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Debug.Assert(Room != null); - return ((IMultiplayerClient)this).UserLeft(Room.Users.Single(u => u.UserID == userId)); + return ((IMultiplayerClient)this).UserKicked(Room.Users.Single(u => u.UserID == userId)); } public override async Task ChangeSettings(MultiplayerRoomSettings settings) From a553942a7ff141ecf4aee4a75bcbc5e58f80816e Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Sat, 14 Aug 2021 13:20:36 +0800 Subject: [PATCH 289/961] update `InitialActivity` on multiplayer `Player` and `SongSelect` --- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 6 ++++++ .../Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 3 +++ osu.Game/Users/UserActivity.cs | 9 +++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 3733b85a5e..7efcec50db 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -11,6 +11,7 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; +using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Multiplayer { @@ -19,8 +20,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } + [Resolved] + private Room room { get; set; } + private LoadingLayer loadingLayer; + protected override UserActivity InitialActivity => new UserActivity.InLobby(room); + /// /// Construct a new instance of multiplayer song select. /// diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index ca1a3710ab..7e9d0a423f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -17,6 +17,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; +using osu.Game.Users; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer @@ -25,6 +26,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { protected override bool PauseOnFocusLost => false; + protected override UserActivity InitialActivity => new UserActivity.MultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + // Disallow fails in multiplayer for now. protected override bool CheckModsAllowFailure() => false; diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index f633773d11..17c028af7d 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -25,9 +25,14 @@ namespace osu.Game.Users public override string Status => "Choosing a beatmap"; } - public class MultiplayerGame : UserActivity + public class MultiplayerGame : SoloGame { - public override string Status => "Playing with others"; + public MultiplayerGame(BeatmapInfo beatmap, RulesetInfo ruleset) + : base(beatmap, ruleset) + { + } + + public override string Status => $@"{base.Status} with others"; } public class Editing : UserActivity From f87f86e671190c2836b95b801fee7be50aa52b1a Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 14 Aug 2021 21:52:09 +0800 Subject: [PATCH 290/961] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Localisation/GameplaySettingsStrings.cs | 2 +- osu.Game/Localisation/OnlineSettingsStrings.cs | 2 +- osu.Game/Localisation/UserInterfaceStrings.cs | 2 +- .../Overlays/Settings/Sections/Gameplay/GeneralSettings.cs | 2 +- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 2 +- .../Overlays/Settings/Sections/Graphics/RendererSettings.cs | 2 +- .../Overlays/Settings/Sections/Online/IntegrationSettings.cs | 2 +- .../Settings/Sections/UserInterface/GeneralSettings.cs | 2 +- .../Settings/Sections/UserInterface/MainMenuSettings.cs | 2 +- osu.Game/Overlays/Settings/SettingsSubsection.cs | 5 +++++ 10 files changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index c63fa5ddcc..868eb6b98a 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -42,7 +42,7 @@ namespace osu.Game.Localisation /// /// "Show difficulty graph on progress bar" /// - public static LocalisableString ShowProgressGraph => new TranslatableString(getKey(@"show_progress_graph"), @"Show difficulty graph on progress bar"); + public static LocalisableString ShowDifficultyGraph => new TranslatableString(getKey(@"show_progress_graph"), @"Show difficulty graph on progress bar"); /// /// "Show health display even when you can't fail" diff --git a/osu.Game/Localisation/OnlineSettingsStrings.cs b/osu.Game/Localisation/OnlineSettingsStrings.cs index 0173cc7cbb..6862f4ac2c 100644 --- a/osu.Game/Localisation/OnlineSettingsStrings.cs +++ b/osu.Game/Localisation/OnlineSettingsStrings.cs @@ -32,7 +32,7 @@ namespace osu.Game.Localisation /// /// "Integrations" /// - public static LocalisableString IntegrationHeader => new TranslatableString(getKey(@"integration_header"), @"Integrations"); + public static LocalisableString IntegrationsHeader => new TranslatableString(getKey(@"integrations_header"), @"Integrations"); /// /// "Discord Rich Presence" diff --git a/osu.Game/Localisation/UserInterfaceStrings.cs b/osu.Game/Localisation/UserInterfaceStrings.cs index fcfaf661dc..4be403edb4 100644 --- a/osu.Game/Localisation/UserInterfaceStrings.cs +++ b/osu.Game/Localisation/UserInterfaceStrings.cs @@ -37,7 +37,7 @@ namespace osu.Game.Localisation /// /// "Hold-to-confirm activation time" /// - public static LocalisableString HoldActivationDelay => new TranslatableString(getKey(@"hold_activation_delay"), @"Hold-to-confirm activation time"); + public static LocalisableString HoldToConfirmActivationTime => new TranslatableString(getKey(@"hold_to_confirm_activation_time"), @"Hold-to-confirm activation time"); /// /// "Main Menu" diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 04332fcdd3..3a0265e453 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay }, new SettingsCheckbox { - LabelText = GameplaySettingsStrings.ShowProgressGraph, + LabelText = GameplaySettingsStrings.ShowDifficultyGraph, Current = config.GetBindable(OsuSetting.ShowProgressGraph) }, new SettingsCheckbox diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 50bd8184ee..124b3b804c 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -146,7 +146,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics { updateResolutionDropdown(); - windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : string.Empty; + windowModeDropdown.WarningText = mode.NewValue != WindowMode.Fullscreen ? GraphicsSettingsStrings.NotFullscreenNote : default; }, true); windowModes.BindCollectionChanged((sender, args) => diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs index 9747f6b373..653f30a018 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/RendererSettings.cs @@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics frameLimiterDropdown.Current.BindValueChanged(limit => { - frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : string.Empty; + frameLimiterDropdown.WarningText = limit.NewValue == FrameSync.Unlimited ? GraphicsSettingsStrings.UnlimitedFramesNote : default; }, true); } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs index f2a516feef..0207f2fd01 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/IntegrationSettings.cs @@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online { public class IntegrationSettings : SettingsSubsection { - protected override LocalisableString Header => OnlineSettingsStrings.IntegrationHeader; + protected override LocalisableString Header => OnlineSettingsStrings.IntegrationsHeader; [BackgroundDependencyLoader] private void load(OsuConfigManager config) diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs index b26363a9da..0afbed5df5 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/GeneralSettings.cs @@ -37,7 +37,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface }, new SettingsSlider { - LabelText = UserInterfaceStrings.HoldActivationDelay, + LabelText = UserInterfaceStrings.HoldToConfirmActivationTime, Current = config.GetBindable(OsuSetting.UIHoldActivationDelay), KeyboardStep = 50 }, diff --git a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs index 976893bf0a..40485a070c 100644 --- a/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/UserInterface/MainMenuSettings.cs @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Settings.Sections.UserInterface user.BindValueChanged(u => { - backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : string.Empty; + backgroundSourceDropdown.WarningText = u.NewValue?.IsSupporter != true ? UserInterfaceStrings.NotSupporterNote : default; }, true); } } diff --git a/osu.Game/Overlays/Settings/SettingsSubsection.cs b/osu.Game/Overlays/Settings/SettingsSubsection.cs index df32424b67..4aa9360452 100644 --- a/osu.Game/Overlays/Settings/SettingsSubsection.cs +++ b/osu.Game/Overlays/Settings/SettingsSubsection.cs @@ -24,6 +24,11 @@ namespace osu.Game.Overlays.Settings protected abstract LocalisableString Header { get; } public IEnumerable FilterableChildren => Children.OfType(); + + // FilterTerms should contains both original string and localised string for user to search. + // Since LocalisableString is unable to get original string at this time (2021-08-14), + // only call .ToString() to use localised one. + // TODO: Update here when FilterTerms accept LocalisableString. public virtual IEnumerable FilterTerms => new[] { Header.ToString() }; public bool MatchingFilter From c2bbe175627ce35f1d63bc7c627b35b4883de5a0 Mon Sep 17 00:00:00 2001 From: kj415j45 Date: Sat, 14 Aug 2021 22:35:15 +0800 Subject: [PATCH 291/961] Rename element in OsuSettings enum `ShowProgressGraph` -> `ShowDifficultyGraph` --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Overlays/Settings/Sections/Gameplay/GeneralSettings.cs | 2 +- osu.Game/Screens/Play/SongProgress.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 60a0d5a0ac..6c7adcc806 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -101,7 +101,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.HitLighting, true); SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); - SetDefault(OsuSetting.ShowProgressGraph, true); + SetDefault(OsuSetting.ShowDifficultyGraph, true); SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true); SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true); SetDefault(OsuSetting.KeyOverlay, false); @@ -217,7 +217,7 @@ namespace osu.Game.Configuration AlwaysPlayFirstComboBreak, FloatingComments, HUDVisibilityMode, - ShowProgressGraph, + ShowDifficultyGraph, ShowHealthDisplayWhenCantFail, FadePlayfieldWhenHealthLow, MouseDisableButtons, diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 353292606f..69aa57082a 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay new SettingsCheckbox { LabelText = "Show difficulty graph on progress bar", - Current = config.GetBindable(OsuSetting.ShowProgressGraph) + Current = config.GetBindable(OsuSetting.ShowDifficultyGraph) }, new SettingsCheckbox { diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index f28622f42e..6aa7e017ce 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Play Objects = drawableRuleset.Objects; } - config.BindWith(OsuSetting.ShowProgressGraph, ShowGraph); + config.BindWith(OsuSetting.ShowDifficultyGraph, ShowGraph); graph.FillColour = bar.FillColour = colours.BlueLighter; } From 4ed06a1021a6b38b49fccd47d0d94b28d92c4227 Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Sat, 14 Aug 2021 22:39:12 +0800 Subject: [PATCH 292/961] apply suggestions --- osu.Game/Rulesets/Ruleset.cs | 2 +- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 8 +------- .../Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 3 --- osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs | 6 ++++++ osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 3 +++ osu.Game/Users/UserActivity.cs | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 9fdaca88fd..98eb374a0d 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -226,7 +226,7 @@ namespace osu.Game.Rulesets /// /// The playing verb to be shown in the . /// - public virtual string PlayingVerb => "Playing solo"; + public virtual string PlayingVerb => "Playing"; /// /// A list of available variant ids. diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 7efcec50db..077ab45b50 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -11,22 +11,16 @@ using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; -using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Multiplayer { public class MultiplayerMatchSongSelect : OnlinePlaySongSelect { [Resolved] - private MultiplayerClient client { get; set; } - - [Resolved] - private Room room { get; set; } + private MultiplayerClient client { get; set; } private LoadingLayer loadingLayer; - protected override UserActivity InitialActivity => new UserActivity.InLobby(room); - /// /// Construct a new instance of multiplayer song select. /// diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 7e9d0a423f..ca1a3710ab 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -17,7 +17,6 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; -using osu.Game.Users; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer @@ -26,8 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { protected override bool PauseOnFocusLost => false; - protected override UserActivity InitialActivity => new UserActivity.MultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); - // Disallow fails in multiplayer for now. protected override bool CheckModsAllowFailure() => false; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index 1502463022..de1b990573 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -17,6 +17,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.Select; +using osu.Game.Users; using osu.Game.Utils; namespace osu.Game.Screens.OnlinePlay @@ -32,6 +33,11 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room), nameof(Room.Playlist))] protected BindableList Playlist { get; private set; } + [Resolved] + private Room room { get; set; } + + protected override UserActivity InitialActivity => new UserActivity.InLobby(room); + protected readonly Bindable> FreeMods = new Bindable>(Array.Empty()); [CanBeNull] diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index 7ba12f5db6..b6f5fe0205 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Scoring; +using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -19,6 +20,8 @@ namespace osu.Game.Screens.Play protected readonly PlaylistItem PlaylistItem; + protected override UserActivity InitialActivity => new UserActivity.MultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + protected RoomSubmittingPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) { diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 17c028af7d..f48c714a30 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -74,7 +74,7 @@ namespace osu.Game.Users public class InLobby : UserActivity { - public override string Status => @"In a multiplayer lobby"; + public override string Status => @"In a lobby"; public readonly Room Room; From 498462dfd0751fbbe480161d4c66487e4f58cc39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Aug 2021 17:24:14 +0200 Subject: [PATCH 293/961] Fix room null-check racing against async schedule --- osu.Game/Online/Multiplayer/MultiplayerClient.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 57dbfbb507..2a0635c98c 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -190,8 +190,7 @@ namespace osu.Game.Online.Multiplayer return joinOrLeaveTaskChain.Add(async () => { await scheduledReset.ConfigureAwait(false); - if (Room != null) - await LeaveRoomInternal().ConfigureAwait(false); + await LeaveRoomInternal().ConfigureAwait(false); }); } From 246a8882ce248f35ba238875db35d281473e12f6 Mon Sep 17 00:00:00 2001 From: LiangXiang Shen Date: Sun, 15 Aug 2021 00:23:14 +0800 Subject: [PATCH 294/961] Update translation key --- osu.Game/Localisation/GameplaySettingsStrings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Localisation/GameplaySettingsStrings.cs b/osu.Game/Localisation/GameplaySettingsStrings.cs index 868eb6b98a..6d6381b429 100644 --- a/osu.Game/Localisation/GameplaySettingsStrings.cs +++ b/osu.Game/Localisation/GameplaySettingsStrings.cs @@ -42,7 +42,7 @@ namespace osu.Game.Localisation /// /// "Show difficulty graph on progress bar" /// - public static LocalisableString ShowDifficultyGraph => new TranslatableString(getKey(@"show_progress_graph"), @"Show difficulty graph on progress bar"); + public static LocalisableString ShowDifficultyGraph => new TranslatableString(getKey(@"show_difficulty_graph"), @"Show difficulty graph on progress bar"); /// /// "Show health display even when you can't fail" From 2ddf28346aa2873bef9cb9edf313f8fe0b52e721 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 14 Aug 2021 19:58:20 +0300 Subject: [PATCH 295/961] PlayerSettingsGroups -> PlayerSettings --- .../Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs | 2 +- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs index f28c2a1d48..14bd8fa6dc 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayerLoader.cs @@ -23,7 +23,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate [BackgroundDependencyLoader] private void load() { - PlayerSettingsGroups.Expire(); + PlayerSettings.Expire(); } protected override void LogoArriving(OsuLogo logo, bool resuming) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 1f8387ac67..a6592e4d24 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -51,7 +51,7 @@ namespace osu.Game.Screens.Play /// /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. /// - protected FillFlowContainer PlayerSettingsGroups; + protected FillFlowContainer PlayerSettings; protected VisualSettings VisualSettings; @@ -145,7 +145,7 @@ namespace osu.Game.Screens.Play Anchor = Anchor.Centre, Origin = Anchor.Centre, }, - PlayerSettingsGroups = new FillFlowContainer + PlayerSettings = new FillFlowContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, From c8fb79666064f6ead2485aeec1757d1407cda909 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 14 Aug 2021 20:14:21 +0300 Subject: [PATCH 296/961] Fix settings notice text class tinting everything with yellow --- osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs | 2 +- osu.Game/Overlays/Settings/SettingsItem.cs | 2 +- osu.Game/Overlays/Settings/SettingsNoticeText.cs | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 2816eb7037..c561b693d8 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Origin = Anchor.TopCentre, Text = TabletSettingsStrings.NoTabletDetected, }, - new SettingsNoticeText + new SettingsNoticeText(colours) { TextAnchor = Anchor.TopCentre, Anchor = Anchor.TopCentre, diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 5d25605360..ef2027fdab 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -73,7 +73,7 @@ namespace osu.Game.Overlays.Settings return; // construct lazily for cases where the label is not needed (may be provided by the Control). - FlowContent.Add(warningText = new SettingsNoticeText { Margin = new MarginPadding { Bottom = 5 } }); + FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } }); } warningText.Alpha = hasValue ? 0 : 1; diff --git a/osu.Game/Overlays/Settings/SettingsNoticeText.cs b/osu.Game/Overlays/Settings/SettingsNoticeText.cs index 6bb4a3f11c..76ecf7edd4 100644 --- a/osu.Game/Overlays/Settings/SettingsNoticeText.cs +++ b/osu.Game/Overlays/Settings/SettingsNoticeText.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -10,10 +9,9 @@ namespace osu.Game.Overlays.Settings { public class SettingsNoticeText : LinkFlowContainer { - [BackgroundDependencyLoader] - private void load(OsuColour colours) + public SettingsNoticeText(OsuColour colours) + : base(s => s.Colour = colours.Yellow) { - Colour = colours.Yellow; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; } From 95943fdb25c763a10849f9dff6dffb4fa7466919 Mon Sep 17 00:00:00 2001 From: Jacob Van Meter Date: Sat, 14 Aug 2021 20:00:26 -0400 Subject: [PATCH 297/961] Add glow to supporter promo on changelog Added glow to the supporter promo at the end of the changelog, as it is on the website. --- .../Changelog/ChangelogSupporterPromo.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index f617b4fc82..46fab30d5e 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -138,14 +138,28 @@ namespace osu.Game.Overlays.Changelog FillMode = FillMode.Fill, Texture = textures.Get(@"Online/supporter-pippi"), }, - new Sprite + new Container { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Width = 75, Height = 75, - Margin = new MarginPadding { Top = 70 }, - Texture = textures.Get(@"Online/supporter-heart"), + Margin = new MarginPadding { Top = 83 }, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.HotPink.Opacity(0.88f), + Offset = new Vector2(0, 0), + Radius = 17, + Roundness = 39f, + }, + Child = new Sprite + { + Width = 75, + Height = 75, + Texture = textures.Get(@"Online/supporter-heart"), + }, }, }; } From 772860232cbbfad9ca85c68d413465405828279b Mon Sep 17 00:00:00 2001 From: Jacob Van Meter Date: Sat, 14 Aug 2021 20:32:38 -0400 Subject: [PATCH 298/961] Removed empty offset and corrected colour --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 46fab30d5e..203a371f43 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -149,8 +149,7 @@ namespace osu.Game.Overlays.Changelog EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, - Colour = Color4.HotPink.Opacity(0.88f), - Offset = new Vector2(0, 0), + Colour = colour.Pink, Radius = 17, Roundness = 39f, }, From 71ccd38bb35e6276205152edb953daedc0affb34 Mon Sep 17 00:00:00 2001 From: Jacob Van Meter Date: Sat, 14 Aug 2021 20:36:43 -0400 Subject: [PATCH 299/961] Corrected pippi background and promo positioning --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 203a371f43..f8613b101e 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -134,6 +134,7 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.Centre, Origin = Anchor.Centre, + Margin = new MarginPadding { Bottom = 28 }, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, Texture = textures.Get(@"Online/supporter-pippi"), @@ -144,7 +145,7 @@ namespace osu.Game.Overlays.Changelog Origin = Anchor.TopCentre, Width = 75, Height = 75, - Margin = new MarginPadding { Top = 83 }, + Margin = new MarginPadding { Top = 70 }, Masking = true, EdgeEffect = new EdgeEffectParameters { From 7d6f7ac75e496c6cff379c7f471e805267e02047 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 15 Aug 2021 02:57:11 +0200 Subject: [PATCH 300/961] Fix mark channel as read error --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 3136a3960d..1937019ef6 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -553,7 +553,7 @@ namespace osu.Game.Online.Chat if (channel.LastMessageId == channel.LastReadId) return; - var message = channel.Messages.LastOrDefault(); + var message = channel.Messages.FindLast(msg => !(msg is LocalMessage)); if (message == null) return; From 6472d85aae3377c7f37bb233aace478cfad8ab06 Mon Sep 17 00:00:00 2001 From: Jacob Van Meter Date: Sat, 14 Aug 2021 21:48:57 -0400 Subject: [PATCH 301/961] Added heart_size constant and adjusted the glow radius value Added heart_size constant and adjusted the glow radius value to be more in line with the website --- .../Overlays/Changelog/ChangelogSupporterPromo.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index f8613b101e..c51f927f9f 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -24,6 +24,7 @@ namespace osu.Game.Overlays.Changelog public class ChangelogSupporterPromo : CompositeDrawable { private const float image_container_width = 164; + private const float heart_size = 75; private readonly FillFlowContainer textContainer; private readonly Container imageContainer; @@ -143,21 +144,21 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Width = 75, - Height = 75, + Width = heart_size, + Height = heart_size, Margin = new MarginPadding { Top = 70 }, Masking = true, EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, Colour = colour.Pink, - Radius = 17, - Roundness = 39f, + Radius = 10, + Roundness = heart_size / 2, }, Child = new Sprite { - Width = 75, - Height = 75, + Width = heart_size, + Height = heart_size, Texture = textures.Get(@"Online/supporter-heart"), }, }, From 2cc096101efabbe8c2e1fa9b16cdc06b06e1e0c9 Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Sun, 15 Aug 2021 18:56:24 +0800 Subject: [PATCH 302/961] trim whitespace --- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 077ab45b50..3733b85a5e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public class MultiplayerMatchSongSelect : OnlinePlaySongSelect { [Resolved] - private MultiplayerClient client { get; set; } + private MultiplayerClient client { get; set; } private LoadingLayer loadingLayer; From d287db796172a213dce4a079e27b22e42a320bc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Sun, 15 Aug 2021 14:48:56 +0200 Subject: [PATCH 303/961] Clamping seekTime to beatmap length --- osu.Game/Screens/Edit/EditorClock.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 772f6ea192..52c95088f3 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -118,6 +118,7 @@ namespace osu.Game.Screens.Edit if (!snapped || ControlPointInfo.TimingPoints.Count == 0) { + seekTime = Math.Clamp(seekTime, 0, TrackLength); SeekSmoothlyTo(seekTime); return; } From f9e2e808743403cafd862f1fd1177a1bc0f8b4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 15:04:14 +0200 Subject: [PATCH 304/961] Add testing for auto-restart behaviour --- .../Visual/Mods/TestSceneModFailCondition.cs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs diff --git a/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs new file mode 100644 index 0000000000..af874cec91 --- /dev/null +++ b/osu.Game.Tests/Visual/Mods/TestSceneModFailCondition.cs @@ -0,0 +1,55 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Play; + +namespace osu.Game.Tests.Visual.Mods +{ + public class TestSceneModFailCondition : ModTestScene + { + private bool restartRequested; + + protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); + + protected override TestPlayer CreateModPlayer(Ruleset ruleset) + { + var player = base.CreateModPlayer(ruleset); + player.RestartRequested = () => restartRequested = true; + return player; + } + + protected override bool AllowFail => true; + + [SetUpSteps] + public void SetUp() + { + AddStep("reset flag", () => restartRequested = false); + } + + [Test] + public void TestRestartOnFailDisabled() => CreateModTest(new ModTestData + { + Autoplay = false, + Mod = new OsuModSuddenDeath(), + PassCondition = () => !restartRequested && Player.ChildrenOfType().Single().State.Value == Visibility.Visible + }); + + [Test] + public void TestRestartOnFailEnabled() => CreateModTest(new ModTestData + { + Autoplay = false, + Mod = new OsuModSuddenDeath + { + Restart = { Value = true } + }, + PassCondition = () => restartRequested && Player.ChildrenOfType().Single().State.Value == Visibility.Hidden + }); + } +} From 2f9f1ba862cf7c54dca3063e0c33dee9fef55c01 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 15 Aug 2021 15:44:23 +0200 Subject: [PATCH 305/961] Add test for `ChannelManager.MarkChannelAsRead` --- .../Chat/TestSceneChannelManager.cs | 57 ++++++++++++++++++- .../API/Requests/MarkChannelAsReadRequest.cs | 10 ++-- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 0ec21a4c7b..7b6d2078ca 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -19,6 +20,7 @@ namespace osu.Game.Tests.Chat { private ChannelManager channelManager; private int currentMessageId; + List sentMessages; [SetUp] public void Setup() => Schedule(() => @@ -34,6 +36,7 @@ namespace osu.Game.Tests.Chat AddStep("register request handling", () => { currentMessageId = 0; + sentMessages = new List(); ((DummyAPIAccess)API).HandleRequest = req => { @@ -44,7 +47,7 @@ namespace osu.Game.Tests.Chat return true; case PostMessageRequest postMessage: - postMessage.TriggerSuccess(new Message(++currentMessageId) + var message = new Message(++currentMessageId) { IsAction = postMessage.Message.IsAction, ChannelId = postMessage.Message.ChannelId, @@ -52,7 +55,10 @@ namespace osu.Game.Tests.Chat Links = postMessage.Message.Links, Timestamp = postMessage.Message.Timestamp, Sender = postMessage.Message.Sender - }); + }; + + sentMessages.Add(message); + postMessage.TriggerSuccess(message); return true; } @@ -83,12 +89,59 @@ namespace osu.Game.Tests.Chat AddAssert("/np command received by channel 2", () => channel2.Messages.Last().Content.Contains("is listening to")); } + [Test] + public void TestMarkAsReadIgnoringLocalMessages() { + Channel channel = null; + + AddStep("join channel and select it", () => + { + channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public)); + + channelManager.CurrentChannel.Value = channel; + }); + + AddStep("post message", () => channelManager.PostMessage("Something interesting")); + AddUntilStep("wait until the message is posted", () => channel.Messages.Count == sentMessages.Count); + + AddStep("post /help command", () => channelManager.PostCommand("help", channel)); + AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel)); + AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel)); + AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel)); + AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel)); + + AddStep("register mark channel as read request handler", () => { + ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) + { + case MarkChannelAsReadRequest markRead: + var isSentMessage = sentMessages.Contains(markRead.Message); + + AddAssert("mark channel as read called with a real message", () => isSentMessage); + + if(isSentMessage) { + markRead.TriggerSuccess(); + } else { + markRead.TriggerFailure(new APIException("unknown message!", null)); + } + + return true; + } + + return false; + }; + }); + + AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel)); + } + private Channel createChannel(int id, ChannelType type) => new Channel(new User()) { Id = id, Name = $"Channel {id}", Topic = $"Topic of channel {id} with type {type}", Type = type, + LastMessageId = 0, }; private class ChannelManagerContainer : CompositeDrawable diff --git a/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs index 95a5d0acbd..594ab2accc 100644 --- a/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs +++ b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs @@ -9,16 +9,16 @@ namespace osu.Game.Online.API.Requests { public class MarkChannelAsReadRequest : APIRequest { - private readonly Channel channel; - private readonly Message message; + public readonly Channel Channel; + public readonly Message Message; public MarkChannelAsReadRequest(Channel channel, Message message) { - this.channel = channel; - this.message = message; + this.Channel = channel; + this.Message = message; } - protected override string Target => $"chat/channels/{channel.Id}/mark-as-read/{message.Id}"; + protected override string Target => $"chat/channels/{Channel.Id}/mark-as-read/{Message.Id}"; protected override WebRequest CreateWebRequest() { From 7d7c5c06f06a3d5f987623defcdc878e518fed26 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 15 Aug 2021 16:02:25 +0200 Subject: [PATCH 306/961] Fix code formatting --- .../Chat/TestSceneChannelManager.cs | 41 ++++++++++--------- .../API/Requests/MarkChannelAsReadRequest.cs | 4 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index 7b6d2078ca..fcb602cb04 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Chat { private ChannelManager channelManager; private int currentMessageId; - List sentMessages; + private List sentMessages; [SetUp] public void Setup() => Schedule(() => @@ -90,46 +90,49 @@ namespace osu.Game.Tests.Chat } [Test] - public void TestMarkAsReadIgnoringLocalMessages() { + public void TestMarkAsReadIgnoringLocalMessages() + { Channel channel = null; AddStep("join channel and select it", () => { channelManager.JoinChannel(channel = createChannel(1, ChannelType.Public)); - channelManager.CurrentChannel.Value = channel; }); AddStep("post message", () => channelManager.PostMessage("Something interesting")); AddUntilStep("wait until the message is posted", () => channel.Messages.Count == sentMessages.Count); - AddStep("post /help command", () => channelManager.PostCommand("help", channel)); AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel)); AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel)); AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel)); AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel)); - AddStep("register mark channel as read request handler", () => { + AddStep("register mark channel as read request handler", () => + { ((DummyAPIAccess)API).HandleRequest = req => + { + switch (req) { - switch (req) - { - case MarkChannelAsReadRequest markRead: - var isSentMessage = sentMessages.Contains(markRead.Message); + case MarkChannelAsReadRequest markRead: + var isSentMessage = sentMessages.Contains(markRead.Message); - AddAssert("mark channel as read called with a real message", () => isSentMessage); + AddAssert("mark channel as read called with a real message", () => isSentMessage); - if(isSentMessage) { - markRead.TriggerSuccess(); - } else { - markRead.TriggerFailure(new APIException("unknown message!", null)); - } + if (isSentMessage) + { + markRead.TriggerSuccess(); + } + else + { + markRead.TriggerFailure(new APIException("unknown message!", null)); + } - return true; - } + return true; + } - return false; - }; + return false; + }; }); AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel)); diff --git a/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs index 594ab2accc..b24669e6d5 100644 --- a/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs +++ b/osu.Game/Online/API/Requests/MarkChannelAsReadRequest.cs @@ -14,8 +14,8 @@ namespace osu.Game.Online.API.Requests public MarkChannelAsReadRequest(Channel channel, Message message) { - this.Channel = channel; - this.Message = message; + Channel = channel; + Message = message; } protected override string Target => $"chat/channels/{Channel.Id}/mark-as-read/{Message.Id}"; From 7c88a1c6dee143dbea7f60530c7fe17acd50cf0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 16:00:22 +0200 Subject: [PATCH 307/961] Add a way to change custom combo colours via `IHasComboColours` `IHasComboColours` was already mutable (via a strange `AddComboColours()` method) and exposing a straight list is easier to work with. `IHasCustomColours` is also similarly externally mutable (in a way which is not easily removable). --- osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs | 5 +++-- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 9 +++++++++ osu.Game/Beatmaps/Formats/LegacyDecoder.cs | 2 +- osu.Game/Skinning/DefaultLegacySkin.cs | 6 ++++-- osu.Game/Skinning/SkinConfiguration.cs | 8 ++++---- osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs | 4 ++-- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs index c15d804a19..aadabec100 100644 --- a/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs +++ b/osu.Game.Tests/Skins/TestSceneSkinConfigurationLookup.cs @@ -133,11 +133,12 @@ namespace osu.Game.Tests.Skins [Test] public void TestEmptyComboColoursNoFallback() { - AddStep("Add custom combo colours to user skin", () => userSource.Configuration.AddComboColours( + AddStep("Add custom combo colours to user skin", () => userSource.Configuration.CustomComboColours = new List + { new Color4(100, 150, 200, 255), new Color4(55, 110, 166, 255), new Color4(75, 125, 175, 255) - )); + }); AddStep("Disallow default colours fallback in beatmap skin", () => beatmapSource.Configuration.AllowDefaultComboColoursFallback = false); diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index 41c85db063..91d960a2fb 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using osuTK.Graphics; @@ -13,9 +14,17 @@ namespace osu.Game.Beatmaps.Formats /// IReadOnlyList ComboColours { get; } + /// + /// The list of custom combo colours. + /// If non-empty, will return these colours; + /// if empty, will fall back to default combo colours. + /// + List CustomComboColours { get; } + /// /// Adds combo colours to the list. /// + [Obsolete("Use SkinConfiguration.ComboColours directly.")] // can be removed 20220215 void AddComboColours(params Color4[] colours); } } diff --git a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs index b39890084f..20080308f9 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDecoder.cs @@ -123,7 +123,7 @@ namespace osu.Game.Beatmaps.Formats { if (!(output is IHasComboColours tHasComboColours)) return; - tHasComboColours.AddComboColours(colour); + tHasComboColours.CustomComboColours.Add(colour); } else { diff --git a/osu.Game/Skinning/DefaultLegacySkin.cs b/osu.Game/Skinning/DefaultLegacySkin.cs index 30192182f3..16ac17546d 100644 --- a/osu.Game/Skinning/DefaultLegacySkin.cs +++ b/osu.Game/Skinning/DefaultLegacySkin.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.IO.Stores; using osu.Game.Extensions; @@ -21,12 +22,13 @@ namespace osu.Game.Skinning : base(skin, new NamespacedResourceStore(resources.Resources, "Skins/Legacy"), resources, string.Empty) { Configuration.CustomColours["SliderBall"] = new Color4(2, 170, 255, 255); - Configuration.AddComboColours( + Configuration.CustomComboColours = new List + { new Color4(255, 192, 0, 255), new Color4(0, 202, 0, 255), new Color4(18, 124, 255, 255), new Color4(242, 24, 57, 255) - ); + }; Configuration.LegacyVersion = 2.7m; } diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs index 25a924c929..a18144246f 100644 --- a/osu.Game/Skinning/SkinConfiguration.cs +++ b/osu.Game/Skinning/SkinConfiguration.cs @@ -27,14 +27,14 @@ namespace osu.Game.Skinning new Color4(242, 24, 57, 255), }; - private readonly List comboColours = new List(); + public List CustomComboColours { get; set; } = new List(); public IReadOnlyList ComboColours { get { - if (comboColours.Count > 0) - return comboColours; + if (CustomComboColours.Count > 0) + return CustomComboColours; if (AllowDefaultComboColoursFallback) return DefaultComboColours; @@ -43,7 +43,7 @@ namespace osu.Game.Skinning } } - public void AddComboColours(params Color4[] colours) => comboColours.AddRange(colours); + void IHasComboColours.AddComboColours(params Color4[] colours) => CustomComboColours.AddRange(colours); public Dictionary CustomColours { get; } = new Dictionary(); diff --git a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs index cdf6a9a2b4..356d2c848c 100644 --- a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs @@ -116,7 +116,7 @@ namespace osu.Game.Tests.Beatmaps { if (hasColours) { - Configuration.AddComboColours(Colours); + Configuration.CustomComboColours = Colours.ToList(); Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR); Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR); Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR); @@ -145,7 +145,7 @@ namespace osu.Game.Tests.Beatmaps { if (hasCustomColours) { - Configuration.AddComboColours(Colours); + Configuration.CustomComboColours = Colours.ToList(); Configuration.CustomColours.Add("HyperDash", HYPER_DASH_COLOUR); Configuration.CustomColours.Add("HyperDashAfterImage", HYPER_DASH_AFTER_IMAGE_COLOUR); Configuration.CustomColours.Add("HyperDashFruit", HYPER_DASH_FRUIT_COLOUR); From 8f698a42f727472723668931713ae4671af2ace0 Mon Sep 17 00:00:00 2001 From: Opelkuh <25430283+Opelkuh@users.noreply.github.com> Date: Sun, 15 Aug 2021 20:35:52 +0200 Subject: [PATCH 308/961] Refactor `MarkChannelAsRead` test assert --- .../Chat/TestSceneChannelManager.cs | 75 +++++++++---------- 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Chat/TestSceneChannelManager.cs b/osu.Game.Tests/Chat/TestSceneChannelManager.cs index fcb602cb04..5e22101e5c 100644 --- a/osu.Game.Tests/Chat/TestSceneChannelManager.cs +++ b/osu.Game.Tests/Chat/TestSceneChannelManager.cs @@ -47,19 +47,11 @@ namespace osu.Game.Tests.Chat return true; case PostMessageRequest postMessage: - var message = new Message(++currentMessageId) - { - IsAction = postMessage.Message.IsAction, - ChannelId = postMessage.Message.ChannelId, - Content = postMessage.Message.Content, - Links = postMessage.Message.Links, - Timestamp = postMessage.Message.Timestamp, - Sender = postMessage.Message.Sender - }; - - sentMessages.Add(message); - postMessage.TriggerSuccess(message); + handlePostMessageRequest(postMessage); + return true; + case MarkChannelAsReadRequest markRead: + handleMarkChannelAsReadRequest(markRead); return true; } @@ -101,41 +93,44 @@ namespace osu.Game.Tests.Chat }); AddStep("post message", () => channelManager.PostMessage("Something interesting")); - AddUntilStep("wait until the message is posted", () => channel.Messages.Count == sentMessages.Count); + AddStep("post /help command", () => channelManager.PostCommand("help", channel)); AddStep("post /me command with no action", () => channelManager.PostCommand("me", channel)); AddStep("post /join command with no channel", () => channelManager.PostCommand("join", channel)); AddStep("post /join command with non-existent channel", () => channelManager.PostCommand("join i-dont-exist", channel)); AddStep("post non-existent command", () => channelManager.PostCommand("non-existent-cmd arg", channel)); - AddStep("register mark channel as read request handler", () => - { - ((DummyAPIAccess)API).HandleRequest = req => - { - switch (req) - { - case MarkChannelAsReadRequest markRead: - var isSentMessage = sentMessages.Contains(markRead.Message); - - AddAssert("mark channel as read called with a real message", () => isSentMessage); - - if (isSentMessage) - { - markRead.TriggerSuccess(); - } - else - { - markRead.TriggerFailure(new APIException("unknown message!", null)); - } - - return true; - } - - return false; - }; - }); - AddStep("mark channel as read", () => channelManager.MarkChannelAsRead(channel)); + AddAssert("channel's last read ID is set to the latest message", () => channel.LastReadId == sentMessages.Last().Id); + } + + private void handlePostMessageRequest(PostMessageRequest request) + { + var message = new Message(++currentMessageId) + { + IsAction = request.Message.IsAction, + ChannelId = request.Message.ChannelId, + Content = request.Message.Content, + Links = request.Message.Links, + Timestamp = request.Message.Timestamp, + Sender = request.Message.Sender + }; + + sentMessages.Add(message); + request.TriggerSuccess(message); + } + + private void handleMarkChannelAsReadRequest(MarkChannelAsReadRequest request) + { + // only accept messages that were sent through the API + if (sentMessages.Contains(request.Message)) + { + request.TriggerSuccess(); + } + else + { + request.TriggerFailure(new APIException("unknown message!", null)); + } } private Channel createChannel(int id, ChannelType type) => new Channel(new User()) From 29a22bd11f4b82304a14a1501ec48a373d4c1651 Mon Sep 17 00:00:00 2001 From: emu1337 Date: Sun, 15 Aug 2021 20:48:00 +0200 Subject: [PATCH 309/961] added rhythm multiplier for strain sections --- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 15 +++++++++++++++ .../Rulesets/Difficulty/Skills/StrainSkill.cs | 7 ++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index f0eb199e5f..b1373cd215 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -34,6 +34,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills { } + private double calculateRhythmBonus(double time) + { + return 1.0; + } + + protected override double StrainValueOf(DifficultyHitObject current) { if (current.BaseObject is Spinner) @@ -66,5 +72,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return (1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.5)) / osuCurrent.StrainTime; } + protected override double GetTotalCurrentStrain(DifficultyHitObject current) + { + return base.GetTotalCurrentStrain(current) * calculateRhythmBonus(current.StartTime); + } + + protected override double GetPeakStrain(double time) + { + return base.GetPeakStrain(time) * calculateRhythmBonus(time); + } } } diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index d4fcefab9b..95b0fe43fc 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -71,7 +71,12 @@ namespace osu.Game.Rulesets.Difficulty.Skills CurrentStrain *= strainDecay(current.DeltaTime); CurrentStrain += StrainValueOf(current) * SkillMultiplier; - currentSectionPeak = Math.Max(CurrentStrain, currentSectionPeak); + currentSectionPeak = Math.Max(GetTotalCurrentStrain(current), currentSectionPeak); + } + + protected virtual double GetTotalCurrentStrain(DifficultyHitObject current) + { + return CurrentStrain; } /// From df43e758ee18c95ca49e36c05e526517b38646b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 16:13:59 +0200 Subject: [PATCH 310/961] Add editable beatmap skin --- osu.Game/Screens/Edit/EditorBeatmap.cs | 5 +- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 59 ++++++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorBeatmapSkin.cs diff --git a/osu.Game/Screens/Edit/EditorBeatmap.cs b/osu.Game/Screens/Edit/EditorBeatmap.cs index 7de98e5e85..3402bf653a 100644 --- a/osu.Game/Screens/Edit/EditorBeatmap.cs +++ b/osu.Game/Screens/Edit/EditorBeatmap.cs @@ -54,7 +54,7 @@ namespace osu.Game.Screens.Edit private readonly Bindable hasTiming = new Bindable(); [CanBeNull] - public readonly ISkin BeatmapSkin; + public readonly EditorBeatmapSkin BeatmapSkin; [Resolved] private BindableBeatDivisor beatDivisor { get; set; } @@ -69,7 +69,8 @@ namespace osu.Game.Screens.Edit public EditorBeatmap(IBeatmap playableBeatmap, ISkin beatmapSkin = null) { PlayableBeatmap = playableBeatmap; - BeatmapSkin = beatmapSkin; + if (beatmapSkin is Skin skin) + BeatmapSkin = new EditorBeatmapSkin(skin); beatmapProcessor = playableBeatmap.BeatmapInfo.Ruleset?.CreateInstance().CreateBeatmapProcessor(PlayableBeatmap); diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs new file mode 100644 index 0000000000..6745f08b80 --- /dev/null +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.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 System; +using System.Linq; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.OpenGL.Textures; +using osu.Framework.Graphics.Textures; +using osu.Game.Audio; +using osu.Game.Skinning; +using osuTK.Graphics; + +namespace osu.Game.Screens.Edit +{ + /// + /// A beatmap skin which is being edited. + /// + public class EditorBeatmapSkin : ISkin + { + public event Action BeatmapSkinChanged; + + /// + /// The combo colours of this skin. + /// If empty, the default combo colours will be used. + /// + public BindableList ComboColours; + + private readonly Skin skin; + + public EditorBeatmapSkin(Skin skin) + { + this.skin = skin; + + ComboColours = new BindableList(); + if (skin.Configuration.ComboColours != null) + ComboColours.AddRange(skin.Configuration.ComboColours.Select(c => (Colour4)c)); + ComboColours.BindCollectionChanged((_, __) => updateColours()); + } + + private void invokeSkinChanged() => BeatmapSkinChanged?.Invoke(); + + private void updateColours() + { + skin.Configuration.CustomComboColours = ComboColours.Select(c => (Color4)c).ToList(); + invokeSkinChanged(); + } + + #region Delegated ISkin implementation + + public Drawable GetDrawableComponent(ISkinComponent component) => skin.GetDrawableComponent(component); + public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT); + public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo); + public IBindable GetConfig(TLookup lookup) => skin.GetConfig(lookup); + + #endregion + } +} From 0d64da8c63f1e6533f62defaddc21d6b6bc727ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 16:14:41 +0200 Subject: [PATCH 311/961] Add skin providing container responding to beatmap skin edits --- .../Screens/Edit/Compose/ComposeScreen.cs | 3 +- .../Edit/EditorSkinProvidingContainer.cs | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs diff --git a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs index 4a1f1196a9..62b3d33069 100644 --- a/osu.Game/Screens/Edit/Compose/ComposeScreen.cs +++ b/osu.Game/Screens/Edit/Compose/ComposeScreen.cs @@ -15,7 +15,6 @@ using osu.Game.Extensions; using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; -using osu.Game.Skinning; namespace osu.Game.Screens.Edit.Compose { @@ -73,7 +72,7 @@ namespace osu.Game.Screens.Edit.Compose { Debug.Assert(ruleset != null); - return new RulesetSkinProvidingContainer(ruleset, EditorBeatmap.PlayableBeatmap, beatmap.Value.Skin).WithChild(content); + return new EditorSkinProvidingContainer(EditorBeatmap).WithChild(content); } #region Input Handling diff --git a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs new file mode 100644 index 0000000000..27563b5a0f --- /dev/null +++ b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.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 osu.Game.Skinning; + +#nullable enable + +namespace osu.Game.Screens.Edit +{ + /// + /// A that fires when users have made a change to the beatmap skin + /// of the map being edited. + /// + public class EditorSkinProvidingContainer : RulesetSkinProvidingContainer + { + private readonly EditorBeatmapSkin? beatmapSkin; + + public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap) + : base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap, editorBeatmap.BeatmapSkin) + { + beatmapSkin = editorBeatmap.BeatmapSkin; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (beatmapSkin != null) + beatmapSkin.BeatmapSkinChanged += TriggerSourceChanged; + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (beatmapSkin != null) + beatmapSkin.BeatmapSkinChanged -= TriggerSourceChanged; + } + } +} From 81280dfd257fe482e0baeab20c828849b26837a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 16:32:26 +0200 Subject: [PATCH 312/961] Use editable skin structure in combo colour picker --- osu.Game/Screens/Edit/Setup/ColoursSection.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/ColoursSection.cs b/osu.Game/Screens/Edit/Setup/ColoursSection.cs index d7e16645f2..05d9855a24 100644 --- a/osu.Game/Screens/Edit/Setup/ColoursSection.cs +++ b/osu.Game/Screens/Edit/Setup/ColoursSection.cs @@ -1,14 +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.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Skinning; -using osuTK.Graphics; namespace osu.Game.Screens.Edit.Setup { @@ -31,9 +27,8 @@ namespace osu.Game.Screens.Edit.Setup } }; - var colours = Beatmap.BeatmapSkin?.GetConfig>(GlobalSkinColours.ComboColours)?.Value; - if (colours != null) - comboColours.Colours.AddRange(colours.Select(c => (Colour4)c)); + if (Beatmap.BeatmapSkin != null) + comboColours.Colours.BindTo(Beatmap.BeatmapSkin.ComboColours); } } } From 6108451449c8b5a56734a28b4fb034226b01ee53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 15 Aug 2021 18:38:01 +0200 Subject: [PATCH 313/961] Retrieve separated skin instance from working beatmap for editing --- .../Beatmaps/Formats/LegacyBeatmapEncoderTest.cs | 2 +- osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs | 2 +- .../Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs | 2 +- osu.Game.Tests/WaveformTestBeatmap.cs | 2 +- osu.Game/Beatmaps/BeatmapManager.cs | 2 +- osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/DummyWorkingBeatmap.cs | 2 +- osu.Game/Beatmaps/WorkingBeatmap.cs | 10 +++++++++- osu.Game/Screens/Edit/Editor.cs | 2 +- osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs | 2 +- osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs | 2 +- osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs | 2 +- osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs | 2 +- osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs | 2 +- 14 files changed, 22 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 059432eeaf..855a75117d 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -169,7 +169,7 @@ namespace osu.Game.Tests.Beatmaps.Formats protected override Track GetBeatmapTrack() => throw new NotImplementedException(); - protected override ISkin GetSkin() => throw new NotImplementedException(); + protected internal override ISkin GetSkin() => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException(); } diff --git a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs index aed28f5f84..3bf6aaac7a 100644 --- a/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs +++ b/osu.Game.Tests/Gameplay/TestSceneStoryboardSamples.cs @@ -204,7 +204,7 @@ namespace osu.Game.Tests.Gameplay this.resources = resources; } - protected override ISkin GetSkin() => new TestSkin("test-sample", resources); + protected internal override ISkin GetSkin() => new TestSkin("test-sample", resources); } private class TestDrawableStoryboardSample : DrawableStoryboardSample diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs index 13e84e335d..e560c81fb2 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBeatmapSkinFallbacks.cs @@ -111,7 +111,7 @@ namespace osu.Game.Tests.Visual.Gameplay this.beatmapSkin = beatmapSkin; } - protected override ISkin GetSkin() => beatmapSkin; + protected internal override ISkin GetSkin() => beatmapSkin; } private class TestOsuRuleset : OsuRuleset diff --git a/osu.Game.Tests/WaveformTestBeatmap.cs b/osu.Game.Tests/WaveformTestBeatmap.cs index 5477e4a0f8..9c85fa0c9c 100644 --- a/osu.Game.Tests/WaveformTestBeatmap.cs +++ b/osu.Game.Tests/WaveformTestBeatmap.cs @@ -53,7 +53,7 @@ namespace osu.Game.Tests protected override Waveform GetWaveform() => new Waveform(trackStore.GetStream(firstAudioFile)); - protected override ISkin GetSkin() => null; + protected internal override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 0d16294c68..4a78ceb299 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -534,7 +534,7 @@ namespace osu.Game.Beatmaps protected override IBeatmap GetBeatmap() => beatmap; protected override Texture GetBackground() => null; protected override Track GetBeatmapTrack() => null; - protected override ISkin GetSkin() => null; + protected internal override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; } } diff --git a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs index d78ffbbfb6..45112ae74c 100644 --- a/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/BeatmapManager_WorkingBeatmap.cs @@ -128,7 +128,7 @@ namespace osu.Game.Beatmaps return storyboard; } - protected override ISkin GetSkin() + protected internal override ISkin GetSkin() { try { diff --git a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs index ea7f45e53f..acfd01a3c8 100644 --- a/osu.Game/Beatmaps/DummyWorkingBeatmap.cs +++ b/osu.Game/Beatmaps/DummyWorkingBeatmap.cs @@ -50,7 +50,7 @@ namespace osu.Game.Beatmaps protected override Track GetBeatmapTrack() => GetVirtualTrack(); - protected override ISkin GetSkin() => null; + protected internal override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; diff --git a/osu.Game/Beatmaps/WorkingBeatmap.cs b/osu.Game/Beatmaps/WorkingBeatmap.cs index 662d24cc83..61760e69b0 100644 --- a/osu.Game/Beatmaps/WorkingBeatmap.cs +++ b/osu.Game/Beatmaps/WorkingBeatmap.cs @@ -327,7 +327,15 @@ namespace osu.Game.Beatmaps public bool SkinLoaded => skin.IsResultAvailable; public ISkin Skin => skin.Value; - protected abstract ISkin GetSkin(); + /// + /// Creates a new skin instance for this beatmap. + /// + /// + /// This should only be called externally in scenarios where it is explicitly desired to get a new instance of a skin + /// (e.g. for editing purposes, to avoid state pollution). + /// For standard reading purposes, should always be used directly. + /// + protected internal abstract ISkin GetSkin(); private readonly RecyclableLazy skin; diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 61a3b0f5cc..e8d919311b 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -153,7 +153,7 @@ namespace osu.Game.Screens.Edit // todo: remove caching of this and consume via editorBeatmap? dependencies.Cache(beatDivisor); - AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.Skin)); + AddInternal(editorBeatmap = new EditorBeatmap(playableBeatmap, loadableBeatmap.GetSkin())); dependencies.CacheAs(editorBeatmap); changeHandler = new EditorChangeHandler(editorBeatmap); dependencies.CacheAs(changeHandler); diff --git a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs index 6f92db98ee..d26856365e 100644 --- a/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs +++ b/osu.Game/Screens/Edit/LegacyEditorBeatmapPatcher.cs @@ -118,7 +118,7 @@ namespace osu.Game.Screens.Edit protected override Track GetBeatmapTrack() => throw new NotImplementedException(); - protected override ISkin GetSkin() => throw new NotImplementedException(); + protected internal override ISkin GetSkin() => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException(); } diff --git a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs index 4935f7fc13..64f1ee4a7a 100644 --- a/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/BeatmapConversionTest.cs @@ -217,7 +217,7 @@ namespace osu.Game.Tests.Beatmaps protected override Track GetBeatmapTrack() => throw new NotImplementedException(); - protected override ISkin GetSkin() => throw new NotImplementedException(); + protected internal override ISkin GetSkin() => throw new NotImplementedException(); public override Stream GetStream(string storagePath) => throw new NotImplementedException(); diff --git a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs index 7ee6c519b7..bb5dd09e16 100644 --- a/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs +++ b/osu.Game/Tests/Beatmaps/HitObjectSampleTest.cs @@ -211,7 +211,7 @@ namespace osu.Game.Tests.Beatmaps this.resources = resources; } - protected override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, resources); + protected internal override ISkin GetSkin() => new LegacyBeatmapSkin(skinBeatmapInfo, resourceStore, resources); } } } diff --git a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs index 356d2c848c..27162b1d66 100644 --- a/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyBeatmapSkinColourTest.cs @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Beatmaps HasColours = hasColours; } - protected override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, HasColours); + protected internal override ISkin GetSkin() => new TestBeatmapSkin(BeatmapInfo, HasColours); } protected class TestBeatmapSkin : LegacyBeatmapSkin diff --git a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs index bfce59c7de..19974701db 100644 --- a/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs +++ b/osu.Game/Tests/Beatmaps/TestWorkingBeatmap.cs @@ -37,7 +37,7 @@ namespace osu.Game.Tests.Beatmaps protected override Storyboard GetStoryboard() => storyboard ?? base.GetStoryboard(); - protected override ISkin GetSkin() => null; + protected internal override ISkin GetSkin() => null; public override Stream GetStream(string storagePath) => null; From f6773522d1652a94ea1618a5482e8d668758dfd7 Mon Sep 17 00:00:00 2001 From: Daniel Kariv <38776931+danielkariv@users.noreply.github.com> Date: Mon, 16 Aug 2021 00:12:27 +0300 Subject: [PATCH 314/961] Correct icons in beatmap details In relation to #13968. Replacing incorrect icons in beatmap details panel to correct ones from BeatmapStatisticsIcon class. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 3f1034759e..21bb75b960 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -78,10 +78,10 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Horizontal, Children = new[] { - length = new Statistic(FontAwesome.Regular.Clock, "Length") { Width = 0.25f }, - bpm = new Statistic(FontAwesome.Regular.Circle, "BPM") { Width = 0.25f }, - circleCount = new Statistic(FontAwesome.Regular.Circle, "Circle Count") { Width = 0.25f }, - sliderCount = new Statistic(FontAwesome.Regular.Circle, "Slider Count") { Width = 0.25f }, + length = new Statistic(BeatmapStatisticsIconType.Length, "Length") { Width = 0.25f }, + bpm = new Statistic(BeatmapStatisticsIconType.Bpm, "BPM") { Width = 0.25f }, + circleCount = new Statistic(BeatmapStatisticsIconType.Circles, "Circle Count") { Width = 0.25f }, + sliderCount = new Statistic(BeatmapStatisticsIconType.Sliders, "Slider Count") { Width = 0.25f }, }, }; } @@ -104,7 +104,7 @@ namespace osu.Game.Overlays.BeatmapSet set => this.value.Text = value; } - public Statistic(IconUsage icon, string name) + public Statistic(BeatmapStatisticsIconType icon, string name) { TooltipText = name; RelativeSizeAxes = Axes.X; @@ -129,11 +129,9 @@ namespace osu.Game.Overlays.BeatmapSet Rotation = 45, Colour = Color4Extensions.FromHex(@"441288"), }, - new SpriteIcon - { + new BeatmapStatisticIcon(icon){ Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, - Icon = icon, Size = new Vector2(12), Colour = Color4Extensions.FromHex(@"f7dd55"), Scale = new Vector2(0.8f), From 38828b6b82976ee3041bce446e9c21b525027ae3 Mon Sep 17 00:00:00 2001 From: Daniel Kariv <38776931+danielkariv@users.noreply.github.com> Date: Mon, 16 Aug 2021 00:40:31 +0300 Subject: [PATCH 315/961] Updating beatmap details icons changes the sizing and add yellow circle so the UI will fit more with osu-web style. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 21bb75b960..757698e1aa 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -129,10 +129,20 @@ namespace osu.Game.Overlays.BeatmapSet Rotation = 45, Colour = Color4Extensions.FromHex(@"441288"), }, - new BeatmapStatisticIcon(icon){ + new SpriteIcon + { Anchor = Anchor.CentreLeft, Origin = Anchor.Centre, - Size = new Vector2(12), + Icon = FontAwesome.Regular.Circle, + Size = new Vector2(10), + Rotation = 0, + Colour = Color4Extensions.FromHex(@"f7dd55"), + }, + new BeatmapStatisticIcon(icon) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.Centre, + Size = new Vector2(10), Colour = Color4Extensions.FromHex(@"f7dd55"), Scale = new Vector2(0.8f), }, From cc3468b4abaec8f0ead7af7431c3b051667c924b Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Mon, 16 Aug 2021 06:32:33 +0800 Subject: [PATCH 316/961] apply suggestions - make `UserActivity.InGame` and derive that to `InSoloGame` and `InMultiplayerGame` - rename `SoloGame` to `InSoloGame` - rename `MultiplayerGame` to `InMultiplayerGame` --- osu.Desktop/DiscordRichPresence.cs | 4 +- .../Online/TestSceneNowPlayingCommand.cs | 2 +- .../Visual/Online/TestSceneUserPanel.cs | 2 +- osu.Game/Online/Chat/NowPlayingCommand.cs | 4 +- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Screens/Play/Player.cs | 2 +- osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 2 +- osu.Game/Users/UserActivity.cs | 44 +++++++++++-------- 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 832d26b0ef..dcb88efeb6 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -139,8 +139,8 @@ namespace osu.Desktop { switch (activity) { - case UserActivity.SoloGame solo: - return solo.Beatmap.ToString(); + case UserActivity.InGame game: + return game.Beatmap.ToString(); case UserActivity.Editing edit: return edit.Beatmap.ToString(); diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 64e80e9f02..366fa8a4af 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPlayActivity() { - AddStep("Set activity", () => api.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo())); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.InSoloGame(new BeatmapInfo(), new RulesetInfo())); AddStep("Run command", () => Add(new NowPlayingCommand())); diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs index c2e9945c99..a048ae2c54 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs @@ -130,7 +130,7 @@ namespace osu.Game.Tests.Visual.Online AddAssert("visit message is not visible", () => !evast.LastVisitMessage.IsPresent); } - private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.SoloGame(null, rulesetStore.GetRuleset(rulesetId)); + private UserActivity soloGameStatusForRuleset(int rulesetId) => new UserActivity.InSoloGame(null, rulesetStore.GetRuleset(rulesetId)); private class TestUserListPanel : UserListPanel { diff --git a/osu.Game/Online/Chat/NowPlayingCommand.cs b/osu.Game/Online/Chat/NowPlayingCommand.cs index 7756591e03..97a2fbdd5c 100644 --- a/osu.Game/Online/Chat/NowPlayingCommand.cs +++ b/osu.Game/Online/Chat/NowPlayingCommand.cs @@ -41,9 +41,9 @@ namespace osu.Game.Online.Chat switch (api.Activity.Value) { - case UserActivity.SoloGame solo: + case UserActivity.InGame game: verb = "playing"; - beatmap = solo.Beatmap; + beatmap = game.Beatmap; break; case UserActivity.Editing edit: diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 98eb374a0d..cd1ff0f218 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets public abstract string ShortName { get; } /// - /// The playing verb to be shown in the . + /// The playing verb to be shown in the . /// public virtual string PlayingVerb => "Playing"; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 09eaf1c543..f1da9fddc7 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -47,7 +47,7 @@ namespace osu.Game.Screens.Play public override bool AllowBackButton => false; // handled by HoldForMenuButton - protected override UserActivity InitialActivity => new UserActivity.SoloGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + protected override UserActivity InitialActivity => new UserActivity.InSoloGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); public override float BackgroundParallaxAmount => 0.1f; diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index b6f5fe0205..f751fb747c 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -20,7 +20,7 @@ namespace osu.Game.Screens.Play protected readonly PlaylistItem PlaylistItem; - protected override UserActivity InitialActivity => new UserActivity.MultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + protected override UserActivity InitialActivity => new UserActivity.InMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); protected RoomSubmittingPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index f48c714a30..a6b2719956 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -25,14 +25,37 @@ namespace osu.Game.Users public override string Status => "Choosing a beatmap"; } - public class MultiplayerGame : SoloGame + public abstract class InGame : UserActivity { - public MultiplayerGame(BeatmapInfo beatmap, RulesetInfo ruleset) + public BeatmapInfo Beatmap { get; } + + public RulesetInfo Ruleset { get; } + + public InGame(BeatmapInfo info, RulesetInfo ruleset) + { + Beatmap = info; + Ruleset = ruleset; + } + } + + public class InMultiplayerGame : InGame + { + public InMultiplayerGame(BeatmapInfo beatmap, RulesetInfo ruleset) : base(beatmap, ruleset) { } - public override string Status => $@"{base.Status} with others"; + public override string Status => $@"{Ruleset.CreateInstance().PlayingVerb} with others"; + } + + public class InSoloGame : InGame + { + public InSoloGame(BeatmapInfo info, RulesetInfo ruleset) + : base(info, ruleset) + { + } + + public override string Status => Ruleset.CreateInstance().PlayingVerb; } public class Editing : UserActivity @@ -47,21 +70,6 @@ namespace osu.Game.Users public override string Status => @"Editing a beatmap"; } - public class SoloGame : UserActivity - { - public BeatmapInfo Beatmap { get; } - - public RulesetInfo Ruleset { get; } - - public SoloGame(BeatmapInfo info, RulesetInfo ruleset) - { - Beatmap = info; - Ruleset = ruleset; - } - - public override string Status => Ruleset.CreateInstance().PlayingVerb; - } - public class Spectating : UserActivity { public override string Status => @"Spectating a game"; From e744629a4167586e87e41ab1ba6da547b7f5a530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Aug 2021 01:01:56 +0200 Subject: [PATCH 317/961] Fix broken obsoletion message --- osu.Game/Beatmaps/Formats/IHasComboColours.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/IHasComboColours.cs b/osu.Game/Beatmaps/Formats/IHasComboColours.cs index 91d960a2fb..853a590595 100644 --- a/osu.Game/Beatmaps/Formats/IHasComboColours.cs +++ b/osu.Game/Beatmaps/Formats/IHasComboColours.cs @@ -24,7 +24,7 @@ namespace osu.Game.Beatmaps.Formats /// /// Adds combo colours to the list. /// - [Obsolete("Use SkinConfiguration.ComboColours directly.")] // can be removed 20220215 + [Obsolete("Use CustomComboColours directly.")] // can be removed 20220215 void AddComboColours(params Color4[] colours); } } From e8e387b549d1f1caa50b790bf1633ece3d0b1b7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 08:02:23 +0900 Subject: [PATCH 318/961] Cache buffered background to fix multiplayer lounge performance Consider this a request for comment. It's the cleanest solution I can come up with without dropping either the blur, or use of `ModelBackedDrawable`. Intended to resolve https://github.com/ppy/osu/issues/14276. --- .../Components/OnlinePlayBackgroundSprite.cs | 6 +-- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 48 +++++++++++++++---- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs index d8dfac496d..e2ba0b03b0 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundSprite.cs @@ -10,12 +10,12 @@ namespace osu.Game.Screens.OnlinePlay.Components { public class OnlinePlayBackgroundSprite : OnlinePlayComposite { - private readonly BeatmapSetCoverType beatmapSetCoverType; + protected readonly BeatmapSetCoverType BeatmapSetCoverType; private UpdateableBeatmapBackgroundSprite sprite; public OnlinePlayBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) { - this.beatmapSetCoverType = beatmapSetCoverType; + BeatmapSetCoverType = beatmapSetCoverType; } [BackgroundDependencyLoader] @@ -33,6 +33,6 @@ namespace osu.Game.Screens.OnlinePlay.Components sprite.Beatmap.Value = Playlist.FirstOrDefault()?.Beatmap.Value; } - protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(beatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; + protected virtual UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index c2ad0285b1..72b63ab4d4 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Logging; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Input; @@ -104,14 +105,9 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new BufferedContainer + new BeatmapBackgroundSprite { - RelativeSizeAxes = Axes.Both, - BlurSigma = new Vector2(10), - Child = new BeatmapBackgroundSprite - { - RelativeSizeAxes = Axes.Both - } + RelativeSizeAxes = Axes.Both }, new Box { @@ -306,11 +302,45 @@ namespace osu.Game.Screens.OnlinePlay private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite { - protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BackgroundSprite { RelativeSizeAxes = Axes.Both }; + protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BlurredBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; - private class BackgroundSprite : UpdateableBeatmapBackgroundSprite + public class BlurredBackgroundSprite : UpdateableBeatmapBackgroundSprite { + public BlurredBackgroundSprite(BeatmapSetCoverType type) + : base(type) + { + } + protected override double LoadDelay => 200; + + protected override Drawable CreateDrawable(BeatmapInfo model) => + new BufferedLoader(base.CreateDrawable(model)); + } + + // This class is an unfortunate requirement due to `LongRunningLoad` requiring direct async loading. + // It means that if the web request fetching the beatmap background takes too long, it will suddenly appear. + internal class BufferedLoader : BufferedContainer + { + private readonly Drawable drawable; + + public BufferedLoader(Drawable drawable) + { + this.drawable = drawable; + + RelativeSizeAxes = Axes.Both; + BlurSigma = new Vector2(10); + CacheDrawnFrameBuffer = true; + } + + [BackgroundDependencyLoader] + private void load() + { + LoadComponentAsync(drawable, d => + { + Add(d); + ForceRedraw(); + }); + } } } From c56b34d2dacabd31463d6b1747421f88983e4de7 Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Mon, 16 Aug 2021 07:06:23 +0800 Subject: [PATCH 319/961] apply code inspection fixes --- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Users/UserActivity.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index cd1ff0f218..3e7479643e 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets public abstract string ShortName { get; } /// - /// The playing verb to be shown in the . + /// The playing verb to be shown in the . /// public virtual string PlayingVerb => "Playing"; diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index a6b2719956..1bbe38b416 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -25,7 +25,7 @@ namespace osu.Game.Users public override string Status => "Choosing a beatmap"; } - public abstract class InGame : UserActivity + public class InGame : UserActivity { public BeatmapInfo Beatmap { get; } @@ -36,6 +36,8 @@ namespace osu.Game.Users Beatmap = info; Ruleset = ruleset; } + + public override string Status => Ruleset.CreateInstance().PlayingVerb; } public class InMultiplayerGame : InGame @@ -45,7 +47,7 @@ namespace osu.Game.Users { } - public override string Status => $@"{Ruleset.CreateInstance().PlayingVerb} with others"; + public override string Status => $@"{base.Status} with others"; } public class InSoloGame : InGame @@ -54,8 +56,6 @@ namespace osu.Game.Users : base(info, ruleset) { } - - public override string Status => Ruleset.CreateInstance().PlayingVerb; } public class Editing : UserActivity From d35886ef196c032075e68bfcc1913f6469187465 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 11:03:49 +0900 Subject: [PATCH 320/961] Reduce frame buffer render scale for blurred background --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 72b63ab4d4..fd265e9978 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -329,6 +329,7 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both; BlurSigma = new Vector2(10); + FrameBufferScale = new Vector2(0.5f); CacheDrawnFrameBuffer = true; } From f0fe79b568724b5151a8b9544438463ee56014a4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 11:04:21 +0900 Subject: [PATCH 321/961] Remove buffered container workarounds for now --- .../Lounge/Components/DrawableRoom.cs | 65 +++++++------------ 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 193fb0cf57..c8ecd65574 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -158,21 +158,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Children = new Drawable[] { // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. - new BufferedContainer + new Box { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Background5, - }, - new OnlinePlayBackgroundSprite - { - RelativeSizeAxes = Axes.Both - }, - } + Colour = colours.Background5, + }, + new OnlinePlayBackgroundSprite + { + RelativeSizeAxes = Axes.Both }, new Container { @@ -187,37 +180,29 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components CornerRadius = corner_radius, Children = new Drawable[] { - // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. - new BufferedContainer + new GridContainer { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + ColumnDimensions = new[] { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, 0.2f) - }, - Content = new[] - { - new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Background5, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f)) - }, - } - } - }, + new Dimension(GridSizeMode.Relative, 0.2f) }, + Content = new[] + { + new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Background5, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f)) + }, + } + } }, new Container { From 76a8d4329fe570a10532d3cb87cd09210523abcf Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Aug 2021 12:43:09 +0900 Subject: [PATCH 322/961] Make TestRoomManager update existing room --- osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs index 2e9c0d1d53..d7c5a0a0e4 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs @@ -38,7 +38,13 @@ namespace osu.Game.Tests.Visual.OnlinePlay public void AddOrUpdateRoom(Room room) { - Rooms.Add(room); + var existing = Rooms.FirstOrDefault(r => r.RoomID.Value != null && r.RoomID.Value == room.RoomID.Value); + + if (existing != null) + existing.CopyFrom(room); + else + Rooms.Add(room); + RoomsUpdated?.Invoke(); } From 3db0b69f9247ae4037a6c6621fa7bcb9b7078f6e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Aug 2021 12:44:12 +0900 Subject: [PATCH 323/961] Throw not implemented exceptions --- .../TestScenePlaylistsMatchSettingsOverlay.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 79af2d3099..98882b659c 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -141,17 +141,11 @@ namespace osu.Game.Tests.Visual.Playlists public IBindableList Rooms => null; - public void AddOrUpdateRoom(Room room) - { - } + public void AddOrUpdateRoom(Room room) => throw new NotImplementedException(); - public void RemoveRoom(Room room) - { - } + public void RemoveRoom(Room room) => throw new NotImplementedException(); - public void ClearRooms() - { - } + public void ClearRooms() => throw new NotImplementedException(); public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) { From 9d9974166379c78ab3208c0c3ffbaf94e985e31a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 06:56:59 +0300 Subject: [PATCH 324/961] Add failing test case --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index b7e92a79a0..3017428039 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -12,6 +12,7 @@ using osu.Game.Configuration; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Screens.Play; +using osu.Game.Skinning; using osuTK.Input; namespace osu.Game.Tests.Visual.Gameplay @@ -142,6 +143,22 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue)); } + [Test] + public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad() + { + HUDVisibilityMode originalConfigValue = default; + + AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); + + AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + + createNew(); + AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded); + AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); + + AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); + } + private void createNew(Action action = null) { AddStep("create overlay", () => From 554b09ac1b28e36416c929397ffb45fa60337caf Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 06:57:45 +0300 Subject: [PATCH 325/961] Fix `SkinnableTargetsContainer` blocked from processing scheduled tasks --- osu.Game/Screens/Play/HUDOverlay.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs index 2cf2555b3e..13df9fefa7 100644 --- a/osu.Game/Screens/Play/HUDOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -57,8 +57,6 @@ namespace osu.Game.Screens.Play private Bindable configVisibilityMode; - private readonly Container visibilityContainer; - private readonly BindableBool replayLoaded = new BindableBool(); private static bool hasShownNotificationOnce; @@ -72,7 +70,7 @@ namespace osu.Game.Screens.Play private readonly SkinnableTargetContainer mainComponents; - private IEnumerable hideTargets => new Drawable[] { visibilityContainer, KeyCounter, topRightElements }; + private IEnumerable hideTargets => new Drawable[] { mainComponents, KeyCounter, topRightElements }; public HUDOverlay(DrawableRuleset drawableRuleset, IReadOnlyList mods) { @@ -84,13 +82,9 @@ namespace osu.Game.Screens.Play Children = new Drawable[] { CreateFailingLayer(), - visibilityContainer = new Container + mainComponents = new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents) { RelativeSizeAxes = Axes.Both, - Child = mainComponents = new SkinnableTargetContainer(SkinnableTarget.MainHUDComponents) - { - RelativeSizeAxes = Axes.Both, - }, }, topRightElements = new FillFlowContainer { From 81f94424713470101867c541b8e83d4dd719e15d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Aug 2021 13:04:06 +0900 Subject: [PATCH 326/961] Inline update/addRoom in usage sites --- .../OnlinePlay/Components/RoomManager.cs | 43 +++++-------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs index ab92adcac7..43bf3a2ce5 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs @@ -57,11 +57,10 @@ namespace osu.Game.Screens.OnlinePlay.Components { joinedRoom.Value = room; - update(room, result); - addRoom(room); + AddOrUpdateRoom(result); + room.CopyFrom(result); // Also copy back to the source model, since this is likely to have been stored elsewhere. - RoomsUpdated?.Invoke(); - onSuccess?.Invoke(room); + onSuccess?.Invoke(result); }; req.Failure += exception => @@ -119,8 +118,14 @@ namespace osu.Game.Screens.OnlinePlay.Components try { - update(room, room); - addRoom(room); + foreach (var pi in room.Playlist) + pi.MapObjects(beatmaps, rulesets); + + var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value); + if (existing == null) + rooms.Add(room); + else + existing.CopyFrom(room); } catch (Exception ex) { @@ -145,32 +150,6 @@ namespace osu.Game.Screens.OnlinePlay.Components notifyRoomsUpdated(); } - /// - /// Updates a local with a remote copy. - /// - /// The local to update. - /// The remote to update with. - private void update(Room local, Room remote) - { - foreach (var pi in remote.Playlist) - pi.MapObjects(beatmaps, rulesets); - - local.CopyFrom(remote); - } - - /// - /// Adds a to the list of available rooms. - /// - /// The to add. - private void addRoom(Room room) - { - var existing = rooms.FirstOrDefault(e => e.RoomID.Value == room.RoomID.Value); - if (existing == null) - rooms.Add(room); - else - existing.CopyFrom(room); - } - private void notifyRoomsUpdated() => Scheduler.AddOnce(() => RoomsUpdated?.Invoke()); } } From b6a2020c59ebd7667d821277fcc25493f07ff4e2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Aug 2021 13:09:04 +0900 Subject: [PATCH 327/961] General refactorings from PR review --- .../Components/ListingPollingComponent.cs | 8 ++++---- .../Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 15 ++++++++------- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 12 ++++++------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index f686326d08..bc6480d05e 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -15,8 +15,8 @@ namespace osu.Game.Screens.OnlinePlay.Components /// public class ListingPollingComponent : RoomPollingComponent { - public IBindable HasPolledOnce => hasPolledOnce; - private readonly Bindable hasPolledOnce = new Bindable(); + public IBindable InitialRoomsReceived => initialRoomsReceived; + private readonly Bindable initialRoomsReceived = new Bindable(); [Resolved] private Bindable currentFilter { get; set; } @@ -30,7 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Components currentFilter.BindValueChanged(_ => { RoomManager.ClearRooms(); - hasPolledOnce.Value = false; + initialRoomsReceived.Value = false; if (IsLoaded) PollImmediately(); @@ -60,7 +60,7 @@ namespace osu.Game.Screens.OnlinePlay.Components foreach (var incoming in result) RoomManager.AddOrUpdateRoom(incoming); - hasPolledOnce.Value = true; + initialRoomsReceived.Value = true; tcs.SetResult(true); }; diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 4e3f37f814..bd2648791c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -45,6 +45,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge AutoSizeAxes = Axes.Both }; + protected ListingPollingComponent ListingPollingComponent { get; private set; } + [Resolved] private Bindable selectedRoom { get; set; } @@ -72,7 +74,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private RoomsContainer roomsContainer; private SearchTextBox searchTextBox; private Dropdown statusDropdown; - private ListingPollingComponent listingPollingComponent; [BackgroundDependencyLoader(true)] private void load([CanBeNull] IdleTracker idleTracker) @@ -86,7 +87,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { - listingPollingComponent = CreatePollingComponent(), + ListingPollingComponent = CreatePollingComponent(), loadingLayer = new LoadingLayer(true), new Container { @@ -186,7 +187,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced()); ruleset.BindValueChanged(_ => UpdateFilter()); - listingPollingComponent.HasPolledOnce.BindValueChanged(_ => updateLoadingLayer()); + ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer()); isIdle.BindValueChanged(_ => updatePollingRate(this.IsCurrentScreen()), true); @@ -337,7 +338,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void updateLoadingLayer() { - if (operationInProgress.Value || !listingPollingComponent.HasPolledOnce.Value) + if (operationInProgress.Value || !ListingPollingComponent.InitialRoomsReceived.Value) loadingLayer.Show(); else loadingLayer.Hide(); @@ -346,11 +347,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private void updatePollingRate(bool isCurrentScreen) { if (!isCurrentScreen) - listingPollingComponent.TimeBetweenPolls.Value = 0; + ListingPollingComponent.TimeBetweenPolls.Value = 0; else - listingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; + ListingPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 120000 : 15000; - Logger.Log($"Polling adjusted (listing: {listingPollingComponent.TimeBetweenPolls.Value})"); + Logger.Log($"Polling adjusted (listing: {ListingPollingComponent.TimeBetweenPolls.Value})"); } protected abstract OsuButton CreateNewRoomButton(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 77db955f0a..97fed2040d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } - private MultiplayerListingPollingComponent listingPollingComponent; + private MultiplayerListingPollingComponent multiplayerListingPollingComponent => (MultiplayerListingPollingComponent)ListingPollingComponent; private readonly IBindable isConnected = new Bindable(); @@ -34,8 +34,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.LoadComplete(); isConnected.BindTo(client.IsConnected); - isConnected.BindValueChanged(c => Scheduler.AddOnce(() => listingPollingComponent.AllowPolling = c.NewValue)); - listingPollingComponent.AllowPolling = isConnected.Value; + isConnected.BindValueChanged(c => Scheduler.AddOnce(() => multiplayerListingPollingComponent.AllowPolling = c.NewValue)); + multiplayerListingPollingComponent.AllowPolling = isConnected.Value; } public override void OnResuming(IScreen last) @@ -47,7 +47,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (last is MultiplayerMatchSubScreen match) { RoomManager.RemoveRoom(match.Room); - listingPollingComponent.PollImmediately(); + multiplayerListingPollingComponent.PollImmediately(); } } @@ -69,7 +69,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override RoomSubScreen CreateRoomSubScreen(Room room) => new MultiplayerMatchSubScreen(room); - protected override ListingPollingComponent CreatePollingComponent() => listingPollingComponent = new MultiplayerListingPollingComponent(); + protected override ListingPollingComponent CreatePollingComponent() => new MultiplayerListingPollingComponent(); protected override void OpenNewRoom(Room room) { @@ -104,7 +104,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } } - protected override Task Poll() => !AllowPolling ? Task.CompletedTask : base.Poll(); + protected override Task Poll() => AllowPolling ? base.Poll() : Task.CompletedTask; } } } From 53c3eccfb50bfc6bd3238fa84e2c371a83b4a388 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 07:21:37 +0300 Subject: [PATCH 328/961] Force HUD visibility mode to "Always" during testing --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 9bb9c24c6b..18e4a6c575 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Configuration; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; using osu.Game.Rulesets.UI; @@ -26,6 +27,9 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private OsuGameBase game { get; set; } + [Resolved] + private OsuConfigManager config { get; set; } + [Resolved] private BeatmapManager beatmapManager { get; set; } @@ -86,6 +90,11 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestSpectatorPlayerInteractiveElementsHidden() { + HUDVisibilityMode originalConfigValue = default; + + AddStep("get original config hud visibility", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); + AddStep("set config hud visibility to always", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always)); + start(new[] { PLAYER_1_ID, PLAYER_2_ID }); loadSpectateScreen(false); @@ -100,6 +109,8 @@ namespace osu.Game.Tests.Visual.Multiplayer !p.ChildrenOfType().Any() && !p.ChildrenOfType().Any() && p.ChildrenOfType().SingleOrDefault()?.ShowHandle == false)); + + AddStep("restore config hud visibility", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); } [Test] From f82ed64aa7afc735f7092b96810c66eb45222b9d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 09:06:56 +0300 Subject: [PATCH 329/961] Fix participant panel null user test no longer functioning properly I guess the changes that involved `MultiplayerTestScene` having a test user lookup cache caused this test case to false-pass silently. Added an explicit assert which ensures the added user indeed has a null `User` value. --- .../TestSceneMultiplayerParticipantsList.cs | 4 +++- .../Multiplayer/TestMultiplayerClient.cs | 2 +- osu.Game/Tests/Visual/TestUserLookupCache.cs | 20 +++++++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index a3e6c8de3b..a44ce87738 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; @@ -48,7 +49,8 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddAssert("one unique panel", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 1); - AddStep("add non-resolvable user", () => Client.AddNullUser(-3)); + AddStep("add non-resolvable user", () => Client.AddNullUser()); + AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1); AddUntilStep("two unique panels", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 2); } diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index 67b79d7390..f2da66d666 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -61,7 +61,7 @@ namespace osu.Game.Tests.Visual.Multiplayer return roomUser; } - public void AddNullUser(int userId) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(userId)); + public void AddNullUser() => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(TestUserLookupCache.NULL_USER_ID)); public void RemoveUser(User user) { diff --git a/osu.Game/Tests/Visual/TestUserLookupCache.cs b/osu.Game/Tests/Visual/TestUserLookupCache.cs index d2941b5bd5..b73e81d0dd 100644 --- a/osu.Game/Tests/Visual/TestUserLookupCache.cs +++ b/osu.Game/Tests/Visual/TestUserLookupCache.cs @@ -10,10 +10,22 @@ namespace osu.Game.Tests.Visual { public class TestUserLookupCache : UserLookupCache { - protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) => Task.FromResult(new User + /// + /// A special user ID which would return a for. + /// As a simulation to what a regular would return in the case of failing to fetch the user. + /// + public const int NULL_USER_ID = -1; + + protected override Task ComputeValueAsync(int lookup, CancellationToken token = default) { - Id = lookup, - Username = $"User {lookup}" - }); + if (lookup == NULL_USER_ID) + return Task.FromResult((User)null); + + return Task.FromResult(new User + { + Id = lookup, + Username = $"User {lookup}" + }); + } } } From 67bac207cfce01649c201721cfca1d595a388ff8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 09:37:29 +0300 Subject: [PATCH 330/961] Cover kicking a multiplayer room user with null `User` --- .../Multiplayer/TestSceneMultiplayerParticipantsList.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs index a44ce87738..c4ebc13245 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerParticipantsList.cs @@ -53,6 +53,11 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("null user added", () => Client.Room.AsNonNull().Users.Count(u => u.User == null) == 1); AddUntilStep("two unique panels", () => this.ChildrenOfType().Select(p => p.User).Distinct().Count() == 2); + + AddStep("kick null user", () => this.ChildrenOfType().Single(p => p.User.User == null) + .ChildrenOfType().Single().TriggerClick()); + + AddAssert("null user kicked", () => Client.Room.AsNonNull().Users.Count == 1); } [Test] From 79cd06278426fbc73c7f90f044e25a2047bed488 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 09:26:00 +0300 Subject: [PATCH 331/961] Let `TeamDisplay` take the full `MultiplayerRoomUser` rather than the underlying `User` --- .../Participants/ParticipantPanel.cs | 2 +- .../Multiplayer/Participants/TeamDisplay.cs | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index 1787480e1f..c4b4dbb777 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -83,7 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants Colour = Color4Extensions.FromHex("#F7E65D"), Alpha = 0 }, - new TeamDisplay(user), + new TeamDisplay(User), new Container { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 5a7073f9de..351b9b3673 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -11,7 +11,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; -using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -19,16 +18,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { internal class TeamDisplay : MultiplayerRoomComposite { - private readonly User user; + private readonly MultiplayerRoomUser user; + private Drawable box; [Resolved] private OsuColour colours { get; set; } - [Resolved] - private MultiplayerClient client { get; set; } - - public TeamDisplay(User user) + public TeamDisplay(MultiplayerRoomUser user) { this.user = user; @@ -61,7 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants } }; - if (user.Id == client.LocalUser?.UserID) + if (Client.LocalUser?.Equals(user) == true) { InternalChild = new OsuClickableContainer { @@ -79,9 +76,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private void changeTeam() { - client.SendMatchRequest(new ChangeTeamRequest + Client.SendMatchRequest(new ChangeTeamRequest { - TeamID = ((client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0, + TeamID = ((Client.LocalUser?.MatchState as TeamVersusUserState)?.TeamID + 1) % 2 ?? 0, }); } @@ -93,7 +90,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants // we don't have a way of knowing when an individual user's state has updated, so just handle on RoomUpdated for now. - var userRoomState = Room?.Users.FirstOrDefault(u => u.UserID == user.Id)?.MatchState; + var userRoomState = Room?.Users.FirstOrDefault(u => u.Equals(user))?.MatchState; const double duration = 400; From 7fe6f6dd149c97a6c0a6bae80ecdcac66691543d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 09:26:45 +0300 Subject: [PATCH 332/961] Fix kick button action asserting and using `User.User.ID` rather than `User.UserID` --- .../Multiplayer/Participants/ParticipantPanel.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs index c4b4dbb777..6f8c735b6e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantPanel.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -168,12 +167,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants Origin = Anchor.Centre, Alpha = 0, Margin = new MarginPadding(4), - Action = () => - { - Debug.Assert(user != null); - - Client.KickUser(user.Id); - } + Action = () => Client.KickUser(User.UserID), }, }, } From 81480ac4fc5ea2e14b7790284e8eec3528329bd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:16:02 +0900 Subject: [PATCH 333/961] Use `PlayerConfiguration` to convey no-seek state --- .../Multiplayer/Spectate/MultiSpectatorPlayer.cs | 4 +--- osu.Game/Screens/Play/Player.cs | 8 ++++---- osu.Game/Screens/Play/PlayerConfiguration.cs | 5 +++++ osu.Game/Screens/Play/SpectatorPlayer.cs | 3 ++- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index 1b1dee5ae2..feb1af770b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// The score containing the player's replay. /// The clock controlling the gameplay running state. public MultiSpectatorPlayer([NotNull] Score score, [NotNull] ISpectatorPlayerClock spectatorPlayerClock) - : base(score) + : base(score, new PlayerConfiguration { AllowSeeking = false }) { this.spectatorPlayerClock = spectatorPlayerClock; } @@ -35,8 +35,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate { spectatorPlayerClock.WaitingOnFrames.BindTo(waitingOnFrames); - AllowUserSeekingState.Value = false; - AllowUserSeekingState.Disabled = true; HUDOverlay.PlayerSettingsOverlay.Expire(); HUDOverlay.HoldToQuit.Expire(); } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index dc37464a61..73bf3f9bda 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,9 +77,9 @@ namespace osu.Game.Screens.Play protected readonly Bindable LocalUserPlaying = new Bindable(); - protected readonly Bindable AllowUserSeekingState = new Bindable(); + private readonly Bindable allowUserSeeking = new Bindable(); - public IBindable AllowUserSeeking => AllowUserSeekingState; + public IBindable AllowUserSeeking => allowUserSeeking; public int RestartCount; @@ -275,8 +275,8 @@ namespace osu.Game.Screens.Play DrawableRuleset.HasReplayLoaded.BindValueChanged(r => { - if (!AllowUserSeekingState.Disabled) - AllowUserSeekingState.Value = r.NewValue; + if (Configuration.AllowSeeking) + allowUserSeeking.Value = r.NewValue; updateGameplayState(); }); diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index 18ee73374f..39c7a7568e 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -20,6 +20,11 @@ namespace osu.Game.Screens.Play /// public bool AllowRestart { get; set; } = true; + /// + /// Whether the player should be allowed to seek in a displayed replay. + /// + public bool AllowSeeking { get; set; } = true; + /// /// Whether the player should be allowed to skip intros/outros, advancing to the start of gameplay or the end of a storyboard. /// diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index f662a479ec..1dae28092a 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -23,7 +23,8 @@ namespace osu.Game.Screens.Play protected override bool CheckModsAllowFailure() => false; // todo: better support starting mid-way through beatmap - public SpectatorPlayer(Score score) + public SpectatorPlayer(Score score, PlayerConfiguration configuration = null) + : base(configuration) { this.score = score; } From 838bcc51b2922f6403a8e459aafe8d8ecde41a4a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:27:19 +0900 Subject: [PATCH 334/961] Avoid new bindable requirement --- osu.Game/Screens/Play/Player.cs | 20 ++++++++------------ osu.Game/Screens/Play/SongProgress.cs | 3 ++- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 73bf3f9bda..c43b701ebf 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -77,10 +77,6 @@ namespace osu.Game.Screens.Play protected readonly Bindable LocalUserPlaying = new Bindable(); - private readonly Bindable allowUserSeeking = new Bindable(); - - public IBindable AllowUserSeeking => allowUserSeeking; - public int RestartCount; [Resolved] @@ -273,13 +269,7 @@ namespace osu.Game.Screens.Play DrawableRuleset.FrameStableClock.IsCatchingUp.BindValueChanged(_ => updateSampleDisabledState()); - DrawableRuleset.HasReplayLoaded.BindValueChanged(r => - { - if (Configuration.AllowSeeking) - allowUserSeeking.Value = r.NewValue; - - updateGameplayState(); - }); + DrawableRuleset.HasReplayLoaded.BindValueChanged(_ => updateGameplayState()); // bind clock into components that require it DrawableRuleset.IsPaused.BindTo(GameplayClockContainer.IsPaused); @@ -592,7 +582,13 @@ namespace osu.Game.Screens.Play /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public void Seek(double time) => GameplayClockContainer.Seek(time); + public void Seek(double time) + { + if (!Configuration.AllowSeeking) + throw new InvalidOperationException($"Seeking has ben disabled by the current {nameof(Configuration)}."); + + GameplayClockContainer.Seek(time); + } private ScheduledDelegate frameStablePlaybackResetDelegate; diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 8debe6243d..3e30cf17b3 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -119,7 +119,8 @@ namespace osu.Game.Screens.Play if (drawableRuleset != null) { - ((IBindable)AllowSeeking).BindTo(player.AllowUserSeeking); + if (player?.Configuration.AllowSeeking == true) + ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); referenceClock = drawableRuleset.FrameStableClock; Objects = drawableRuleset.Objects; From ae8a1adae838648807431fec10b41826abbd9849 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:47:57 +0900 Subject: [PATCH 335/961] Allow seeking via `Player.Seek` even if disabled --- osu.Game/Screens/Play/Player.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index c43b701ebf..09eaf1c543 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -582,13 +582,7 @@ namespace osu.Game.Screens.Play /// Seek to a specific time in gameplay. /// /// The destination time to seek to. - public void Seek(double time) - { - if (!Configuration.AllowSeeking) - throw new InvalidOperationException($"Seeking has ben disabled by the current {nameof(Configuration)}."); - - GameplayClockContainer.Seek(time); - } + public void Seek(double time) => GameplayClockContainer.Seek(time); private ScheduledDelegate frameStablePlaybackResetDelegate; From 8d45f86bd3ded0bb0b7c901c3fb30e1b1f7fff93 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:48:40 +0900 Subject: [PATCH 336/961] Rename variable to better reflect its purpose --- .../OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs | 2 +- osu.Game/Screens/Play/PlayerConfiguration.cs | 4 ++-- osu.Game/Screens/Play/SongProgress.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs index feb1af770b..ececa1e497 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// The score containing the player's replay. /// The clock controlling the gameplay running state. public MultiSpectatorPlayer([NotNull] Score score, [NotNull] ISpectatorPlayerClock spectatorPlayerClock) - : base(score, new PlayerConfiguration { AllowSeeking = false }) + : base(score, new PlayerConfiguration { AllowUserInteraction = false }) { this.spectatorPlayerClock = spectatorPlayerClock; } diff --git a/osu.Game/Screens/Play/PlayerConfiguration.cs b/osu.Game/Screens/Play/PlayerConfiguration.cs index 39c7a7568e..3aa424e5d5 100644 --- a/osu.Game/Screens/Play/PlayerConfiguration.cs +++ b/osu.Game/Screens/Play/PlayerConfiguration.cs @@ -21,9 +21,9 @@ namespace osu.Game.Screens.Play public bool AllowRestart { get; set; } = true; /// - /// Whether the player should be allowed to seek in a displayed replay. + /// Whether the player should be able to interact with this player instance. /// - public bool AllowSeeking { get; set; } = true; + public bool AllowUserInteraction { get; set; } = true; /// /// Whether the player should be allowed to skip intros/outros, advancing to the start of gameplay or the end of a storyboard. diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 3e30cf17b3..b27a9c5f5d 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -119,7 +119,7 @@ namespace osu.Game.Screens.Play if (drawableRuleset != null) { - if (player?.Configuration.AllowSeeking == true) + if (player?.Configuration.AllowUserInteraction == true) ((IBindable)AllowSeeking).BindTo(drawableRuleset.HasReplayLoaded); referenceClock = drawableRuleset.FrameStableClock; From fc89f2bac4a3971835beeeb104a10026dfb13782 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:56:48 +0900 Subject: [PATCH 337/961] Revert "Rename element in OsuSettings enum" This reverts commit c2bbe175627ce35f1d63bc7c627b35b4883de5a0. --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Overlays/Settings/Sections/Gameplay/GeneralSettings.cs | 2 +- osu.Game/Screens/Play/SongProgress.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6c7adcc806..60a0d5a0ac 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -101,7 +101,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.HitLighting, true); SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always); - SetDefault(OsuSetting.ShowDifficultyGraph, true); + SetDefault(OsuSetting.ShowProgressGraph, true); SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true); SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true); SetDefault(OsuSetting.KeyOverlay, false); @@ -217,7 +217,7 @@ namespace osu.Game.Configuration AlwaysPlayFirstComboBreak, FloatingComments, HUDVisibilityMode, - ShowDifficultyGraph, + ShowProgressGraph, ShowHealthDisplayWhenCantFail, FadePlayfieldWhenHealthLow, MouseDisableButtons, diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs index 69aa57082a..353292606f 100644 --- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs @@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay new SettingsCheckbox { LabelText = "Show difficulty graph on progress bar", - Current = config.GetBindable(OsuSetting.ShowDifficultyGraph) + Current = config.GetBindable(OsuSetting.ShowProgressGraph) }, new SettingsCheckbox { diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index 6aa7e017ce..f28622f42e 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -125,7 +125,7 @@ namespace osu.Game.Screens.Play Objects = drawableRuleset.Objects; } - config.BindWith(OsuSetting.ShowDifficultyGraph, ShowGraph); + config.BindWith(OsuSetting.ShowProgressGraph, ShowGraph); graph.FillColour = bar.FillColour = colours.BlueLighter; } From 71fab416d8902bbf6b1657de800773e0f78fa2bc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 16:59:59 +0900 Subject: [PATCH 338/961] Add a note against `OsuSetting` --- osu.Game/Configuration/OsuConfigManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 60a0d5a0ac..9b0d7f51da 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -201,6 +201,8 @@ namespace osu.Game.Configuration public Func LookupKeyBindings { get; set; } } + // IMPORTANT: These are used in user configuration files. + // The naming of these keys should not be changed once they are deployed in a release, unless migration logic is also added. public enum OsuSetting { Ruleset, From 1c7cbc862156659d31651b3cfb748d4490e6ac6b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 17:14:13 +0900 Subject: [PATCH 339/961] Add missing `readonly` keyword to new bindable --- osu.Game/Screens/Edit/EditorBeatmapSkin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs index 6745f08b80..429df85904 100644 --- a/osu.Game/Screens/Edit/EditorBeatmapSkin.cs +++ b/osu.Game/Screens/Edit/EditorBeatmapSkin.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit /// The combo colours of this skin. /// If empty, the default combo colours will be used. /// - public BindableList ComboColours; + public readonly BindableList ComboColours; private readonly Skin skin; From db1a0ebb55448903587ce59bbdf99c5ed90744a5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 16 Aug 2021 18:46:44 +0900 Subject: [PATCH 340/961] Fix preview track crashes --- .../BeatmapListing/Panels/PlayButton.cs | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs index 4bbc3569fe..3aa9aa5ca5 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/PlayButton.cs @@ -139,19 +139,24 @@ namespace osu.Game.Overlays.BeatmapListing.Panels LoadComponentAsync(Preview = previewTrackManager.Get(beatmapSet), preview => { - // beatmapset may have changed. - if (Preview != preview) - return; + // Make sure that we schedule to after the next audio frame to fix crashes in single-threaded execution. + // See: https://github.com/ppy/osu-framework/issues/4692 + Schedule(() => + { + // beatmapset may have changed. + if (Preview != preview) + return; - AddInternal(preview); - loading = false; - // make sure that the update of value of Playing (and the ensuing value change callbacks) - // are marshaled back to the update thread. - preview.Stopped += () => Schedule(() => playing.Value = false); + AddInternal(preview); + loading = false; + // make sure that the update of value of Playing (and the ensuing value change callbacks) + // are marshaled back to the update thread. + preview.Stopped += () => Schedule(() => playing.Value = false); - // user may have changed their mind. - if (playing.Value) - attemptStart(); + // user may have changed their mind. + if (playing.Value) + attemptStart(); + }); }); } else From 855fff1486477eb490ed851a33a26be57b96c095 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 12:47:56 +0300 Subject: [PATCH 341/961] Fix `DifficultyAdjustSettingsControl.SliderControl` not following up with the current pattern This was causing any `ValueChanged` event bind (such as the one in `SettingsItem` to invoke `SettingsChanged`) to be overwritten when `Current` is set afterwards. --- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 067657159b..186514e868 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -91,7 +91,13 @@ namespace osu.Game.Rulesets.Mods { // This is required as SettingsItem relies heavily on this bindable for internal use. // The actual update flow is done via the bindable provided in the constructor. - public Bindable Current { get; set; } = new Bindable(); + private readonly BindableWithCurrent current = new BindableWithCurrent(); + + public Bindable Current + { + get => current.Current; + set => current.Current = value; + } public SliderControl(BindableNumber currentNumber) { From 6653a78e659774213635568d5fd2bdcc7d693170 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 12:48:49 +0300 Subject: [PATCH 342/961] Add test coverage --- .../TestSceneModDifficultyAdjustSettings.cs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs index e0d76b3e4a..f8652573f4 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModDifficultyAdjustSettings.cs @@ -1,8 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; +using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -174,6 +176,60 @@ namespace osu.Game.Tests.Visual.UserInterface checkBindableAtValue("Circle Size", null); } + [Test] + public void TestModSettingChangeTracker() + { + ModSettingChangeTracker tracker = null; + Queue settingsChangedQueue = null; + + setBeatmapWithDifficultyParameters(5); + + AddStep("add mod settings change tracker", () => + { + settingsChangedQueue = new Queue(); + + tracker = new ModSettingChangeTracker(modDifficultyAdjust.Yield()) + { + SettingChanged = settingsChangedQueue.Enqueue + }; + }); + + AddAssert("no settings changed", () => settingsChangedQueue.Count == 0); + + setSliderValue("Circle Size", 3); + + settingsChangedFired(); + + setSliderValue("Circle Size", 5); + checkBindableAtValue("Circle Size", 5); + + settingsChangedFired(); + + AddStep("reset mod settings", () => modDifficultyAdjust.CircleSize.SetDefault()); + checkBindableAtValue("Circle Size", null); + + settingsChangedFired(); + + setExtendedLimits(true); + + settingsChangedFired(); + + AddStep("dispose tracker", () => + { + tracker.Dispose(); + tracker = null; + }); + + void settingsChangedFired() + { + AddAssert("setting changed event fired", () => + { + settingsChangedQueue.Dequeue(); + return settingsChangedQueue.Count == 0; + }); + } + } + private void resetToDefault(string name) { AddStep($"Reset {name} to default", () => From c191b3812529e9fdd0f47488fd22e21e6398ff9b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:40:34 +0900 Subject: [PATCH 343/961] Reduce transform overhead of `RestoreDefaultValueButton` --- osu.Game/Overlays/RestoreDefaultValueButton.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index fd3ee16fe6..62f5222012 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; @@ -38,7 +39,9 @@ namespace osu.Game.Overlays current.ValueChanged += _ => UpdateState(); current.DefaultChanged += _ => UpdateState(); current.DisabledChanged += _ => UpdateState(); - UpdateState(); + + if (IsLoaded) + UpdateState(); } } @@ -81,7 +84,10 @@ namespace osu.Game.Overlays protected override void LoadComplete() { base.LoadComplete(); - UpdateState(); + + // avoid unnecessary transforms on first display. + Alpha = currentAlpha; + Colour = currentColour; } public LocalisableString TooltipText => "revert to default"; @@ -101,14 +107,16 @@ namespace osu.Game.Overlays public void UpdateState() => Scheduler.AddOnce(updateState); + private float currentAlpha => current.IsDefault ? 0f : hovering && !current.Disabled ? 1f : 0.65f; + private ColourInfo currentColour => current.Disabled ? Color4.Gray : buttonColour; + private void updateState() { if (current == null) return; - this.FadeTo(current.IsDefault ? 0f : - hovering && !current.Disabled ? 1f : 0.65f, 200, Easing.OutQuint); - this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint); + this.FadeTo(currentAlpha, 200, Easing.OutQuint); + this.FadeColour(currentColour, 200, Easing.OutQuint); } } } From 4b975ca10d34211f6555ff0e98b49c99f23981cb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:43:02 +0900 Subject: [PATCH 344/961] Add better test coverage of `SettingsPanel` --- .../Visual/Settings/TestSceneSettingsPanel.cs | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs index 115d2fec7d..0af77b3b5a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsPanel.cs @@ -4,6 +4,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Settings @@ -11,27 +12,39 @@ namespace osu.Game.Tests.Visual.Settings [TestFixture] public class TestSceneSettingsPanel : OsuTestScene { - private readonly SettingsPanel settings; - private readonly DialogOverlay dialogOverlay; + private SettingsPanel settings; + private DialogOverlay dialogOverlay; - public TestSceneSettingsPanel() + [SetUpSteps] + public void SetUpSteps() { - settings = new SettingsOverlay + AddStep("create settings", () => { - State = { Value = Visibility.Visible } - }; - Add(dialogOverlay = new DialogOverlay - { - Depth = -1 + settings?.Expire(); + + Add(settings = new SettingsOverlay + { + State = { Value = Visibility.Visible } + }); }); } + [Test] + public void ToggleVisibility() + { + AddWaitStep("wait some", 5); + AddToggleStep("toggle editor visibility", visible => settings.ToggleVisibility()); + } + [BackgroundDependencyLoader] private void load() { - Dependencies.Cache(dialogOverlay); + Add(dialogOverlay = new DialogOverlay + { + Depth = -1 + }); - Add(settings); + Dependencies.Cache(dialogOverlay); } } } From cecb312e7703e1ebacf023a13db78159607b9407 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:44:00 +0900 Subject: [PATCH 345/961] Ensure `TakeFocus` does not crash when not yet loaded --- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index f77a3109c9..4a42027964 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -22,7 +22,10 @@ namespace osu.Game.Graphics.UserInterface public void TakeFocus() { - if (allowImmediateFocus) GetContainingInputManager().ChangeFocus(this); + if (!allowImmediateFocus) + return; + + Schedule(() => GetContainingInputManager().ChangeFocus(this)); } public bool HoldFocus From e39a295c5c417ec6d71ded0f07b1029849436c89 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Aug 2021 13:45:50 +0300 Subject: [PATCH 346/961] Hide tablet settings content when input handler is disabled --- .../Settings/Sections/Input/TabletSettings.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index c561b693d8..8303fee3ef 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -22,6 +22,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { private readonly ITabletHandler tabletHandler; + private readonly Bindable enabled = new BindableBool(true); + private readonly Bindable areaOffset = new Bindable(); private readonly Bindable areaSize = new Bindable(); private readonly IBindable tablet = new Bindable(); @@ -74,7 +76,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input LabelText = CommonStrings.Enabled, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Current = tabletHandler.Enabled + Current = enabled, }, noTabletMessage = new FillFlowContainer { @@ -194,6 +196,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input { base.LoadComplete(); + enabled.BindTo(tabletHandler.Enabled); + enabled.BindValueChanged(_ => Scheduler.AddOnce(updateVisibility)); + rotation.BindTo(tabletHandler.Rotation); areaOffset.BindTo(tabletHandler.AreaOffset); @@ -239,7 +244,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input tablet.BindTo(tabletHandler.Tablet); tablet.BindValueChanged(val => { - Scheduler.AddOnce(toggleVisibility); + Scheduler.AddOnce(updateVisibility); var tab = val.NewValue; @@ -259,8 +264,15 @@ namespace osu.Game.Overlays.Settings.Sections.Input }, true); } - private void toggleVisibility() + private void updateVisibility() { + if (!tabletHandler.Enabled.Value) + { + mainSettings.Hide(); + noTabletMessage.Hide(); + return; + } + bool tabletFound = tablet.Value != null; if (!tabletFound) From 7bebbf9f7400e068b1378e0b6b7eec0711c8d14f Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 16 Aug 2021 12:46:41 +0200 Subject: [PATCH 347/961] Mark format strings as verbatim. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 2 +- osu.Game/Screens/Select/Details/UserRatings.cs | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index ce348bd753..ed7676aa21 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -67,8 +67,8 @@ namespace osu.Game.Overlays.BeatmapSet length.TooltipText = BeatmapsetsStrings.ShowStatsTotalLength(TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration()); length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration(); - circleCount.Value = beatmap.OnlineInfo.CircleCount.ToLocalisableString("N0"); - sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToLocalisableString("N0"); + circleCount.Value = beatmap.OnlineInfo.CircleCount.ToLocalisableString(@"N0"); + sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToLocalisableString(@"N0"); } } diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index d370e57f14..b1e9abe3aa 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays.BeatmapSet int playCount = beatmap?.OnlineInfo?.PlayCount ?? 0; var rate = playCount != 0 ? (float)passCount / playCount : 0; - successPercent.Text = rate.ToLocalisableString("0.#%"); + successPercent.Text = rate.ToLocalisableString(@"0.#%"); successRate.Length = rate; percentContainer.ResizeWidthTo(successRate.Length, 250, Easing.InOutCubic); diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index a45bcd0666..a7f28b932a 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -37,8 +37,8 @@ namespace osu.Game.Screens.Select.Details if (metrics == null) { - negativeRatings.Text = 0.ToLocalisableString("N0"); - positiveRatings.Text = 0.ToLocalisableString("N0"); + negativeRatings.Text = 0.ToLocalisableString(@"N0"); + positiveRatings.Text = 0.ToLocalisableString(@"N0"); ratingsBar.Length = 0; graph.Values = new float[rating_range]; } @@ -49,8 +49,8 @@ namespace osu.Game.Screens.Select.Details var negativeCount = ratings.Take(rating_range / 2).Sum(); var totalCount = ratings.Sum(); - negativeRatings.Text = negativeCount.ToLocalisableString("N0"); - positiveRatings.Text = (totalCount - negativeCount).ToLocalisableString("N0"); + negativeRatings.Text = negativeCount.ToLocalisableString(@"N0"); + positiveRatings.Text = (totalCount - negativeCount).ToLocalisableString(@"N0"); ratingsBar.Length = totalCount == 0 ? 0 : (float)negativeCount / totalCount; graph.Values = ratings.Take(rating_range).Select(r => (float)r); } @@ -90,14 +90,14 @@ namespace osu.Game.Screens.Select.Details { negativeRatings = new OsuSpriteText { - Text = 0.ToLocalisableString("N0"), + Text = 0.ToLocalisableString(@"N0"), Font = OsuFont.GetFont(size: 12) }, positiveRatings = new OsuSpriteText { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, - Text = 0.ToLocalisableString("N0"), + Text = 0.ToLocalisableString(@"N0"), Font = OsuFont.GetFont(size: 12) }, }, From c0130da2359ad8947eebdf1a2743cbc2e31e5765 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:44:12 +0900 Subject: [PATCH 348/961] Avoid running initial layout transform in `LayoutSettings` --- .../Overlays/Settings/Sections/Graphics/LayoutSettings.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 91208cb78a..277e344d84 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -97,8 +97,6 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - AutoSizeDuration = transition_duration, - AutoSizeEasing = Easing.OutQuint, Masking = true, Children = new[] { @@ -177,6 +175,9 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingMode.BindValueChanged(mode => { scalingSettings.ClearTransforms(); + + scalingSettings.AutoSizeDuration = transition_duration; + scalingSettings.AutoSizeEasing = Easing.OutQuint; scalingSettings.AutoSizeAxes = mode.NewValue != ScalingMode.Off ? Axes.Y : Axes.None; if (mode.NewValue == ScalingMode.Off) From 92ad66c86c857b7854064c6d6e87b6b107d472ca Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:56:02 +0900 Subject: [PATCH 349/961] Remove transform overhead from `OsuDropdown` on initial display --- osu.Game/Graphics/UserInterface/OsuDropdown.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 61dd5fb2d9..42f628a75a 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -69,6 +69,7 @@ namespace osu.Game.Graphics.UserInterface BackgroundColour = Color4.Black.Opacity(0.5f); MaskingContainer.CornerRadius = corner_radius; + Alpha = 0; // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring ItemsContainer.Padding = new MarginPadding(5); @@ -94,9 +95,11 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateClose() { - this.FadeOut(300, Easing.OutQuint); if (wasOpened) + { + this.FadeOut(300, Easing.OutQuint); sampleClose?.Play(); + } } // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring From 237d3e656b72b2827e04a5228dae4064926a86e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 18:58:26 +0900 Subject: [PATCH 350/961] Remove initial transform overhead of `Nub` --- osu.Game/Graphics/UserInterface/Nub.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 8d686e8c2f..cbf3e6b3aa 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -6,6 +6,7 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -57,18 +58,13 @@ namespace osu.Game.Graphics.UserInterface EdgeEffect = new EdgeEffectParameters { - Colour = GlowColour, + Colour = GlowColour.Opacity(0), Type = EdgeEffectType.Glow, Radius = 10, Roundness = 8, }; } - protected override void LoadComplete() - { - FadeEdgeEffectTo(0); - } - private bool glowing; public bool Glowing From 8d051d9fa0d6c692bc740ec155d0a1bf1914cc7c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:16:48 +0900 Subject: [PATCH 351/961] Avoid multiple synchronous overheads in `SettingsItem` --- osu.Game/Overlays/Settings/SettingsItem.cs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index ef2027fdab..c35690151c 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -93,15 +93,13 @@ namespace osu.Game.Overlays.Settings public bool MatchingFilter { - set => this.FadeTo(value ? 1 : 0); + set => Alpha = value ? 1 : 0; } public bool FilteringActive { get; set; } public event Action SettingChanged; - private readonly RestoreDefaultValueButton restoreDefaultButton; - protected SettingsItem() { RelativeSizeAxes = Axes.X; @@ -110,7 +108,6 @@ namespace osu.Game.Overlays.Settings InternalChildren = new Drawable[] { - restoreDefaultButton = new RestoreDefaultValueButton(), FlowContent = new FillFlowContainer { RelativeSizeAxes = Axes.X, @@ -122,7 +119,11 @@ namespace osu.Game.Overlays.Settings }, }, }; + } + [BackgroundDependencyLoader] + private void load() + { // all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is // never loaded, but requires bindable storage. if (controlWithCurrent == null) @@ -130,14 +131,15 @@ namespace osu.Game.Overlays.Settings controlWithCurrent.Current.ValueChanged += _ => SettingChanged?.Invoke(); controlWithCurrent.Current.DisabledChanged += _ => updateDisabled(); - } - - protected override void LoadComplete() - { - base.LoadComplete(); + // intentionally done before LoadComplete to avoid overhead. if (ShowsDefaultIndicator) - restoreDefaultButton.Current = controlWithCurrent.Current; + { + AddInternal(new RestoreDefaultValueButton + { + Current = controlWithCurrent.Current, + }); + } } private void updateDisabled() From b541550ea97516b877363c2d0509848450b02a40 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:17:36 +0900 Subject: [PATCH 352/961] Avoid initial synchronous dropdown population overhead in `AudioDevicesSettings` --- .../Sections/Audio/AudioDevicesSettings.cs | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs index d64f176468..2354475498 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/AudioDevicesSettings.cs @@ -20,17 +20,26 @@ namespace osu.Game.Overlays.Settings.Sections.Audio private SettingsDropdown dropdown; - protected override void Dispose(bool isDisposing) + [BackgroundDependencyLoader] + private void load() { - base.Dispose(isDisposing); - - if (audio != null) + Children = new Drawable[] { - audio.OnNewDevice -= onDeviceChanged; - audio.OnLostDevice -= onDeviceChanged; - } + dropdown = new AudioDeviceSettingsDropdown + { + Keywords = new[] { "speaker", "headphone", "output" } + } + }; + + updateItems(); + + audio.OnNewDevice += onDeviceChanged; + audio.OnLostDevice += onDeviceChanged; + dropdown.Current = audio.AudioDevice; } + private void onDeviceChanged(string name) => updateItems(); + private void updateItems() { var deviceItems = new List { string.Empty }; @@ -49,26 +58,15 @@ namespace osu.Game.Overlays.Settings.Sections.Audio dropdown.Items = deviceItems.Distinct().ToList(); } - private void onDeviceChanged(string name) => updateItems(); - - protected override void LoadComplete() + protected override void Dispose(bool isDisposing) { - base.LoadComplete(); + base.Dispose(isDisposing); - Children = new Drawable[] + if (audio != null) { - dropdown = new AudioDeviceSettingsDropdown - { - Keywords = new[] { "speaker", "headphone", "output" } - } - }; - - updateItems(); - - dropdown.Current = audio.AudioDevice; - - audio.OnNewDevice += onDeviceChanged; - audio.OnLostDevice += onDeviceChanged; + audio.OnNewDevice -= onDeviceChanged; + audio.OnLostDevice -= onDeviceChanged; + } } private class AudioDeviceSettingsDropdown : SettingsDropdown From c6bd8520a7464f43e4ef558fd61d0015c1e1f171 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:18:39 +0900 Subject: [PATCH 353/961] Add basic asynchronous loading pattern to `SettingsPanel` --- osu.Game/Overlays/SettingsPanel.cs | 93 ++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index f1c41c4b50..c191f61e60 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osuTK; using osuTK.Graphics; @@ -13,6 +14,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -58,6 +60,8 @@ namespace osu.Game.Overlays private readonly bool showSidebar; + private LoadingLayer loading; + protected SettingsPanel(bool showSidebar) { this.showSidebar = showSidebar; @@ -86,45 +90,69 @@ namespace osu.Game.Overlays Colour = OsuColour.Gray(0.05f), Alpha = 1, }, - SectionsContainer = new SettingsSectionsContainer + loading = new LoadingLayer { - Masking = true, - RelativeSizeAxes = Axes.Both, - ExpandableHeader = CreateHeader(), - FixedHeader = searchTextBox = new SeekLimitedSearchTextBox - { - RelativeSizeAxes = Axes.X, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Width = 0.95f, - Margin = new MarginPadding - { - Top = 20, - Bottom = 20 - }, - }, - Footer = CreateFooter() - }, + State = { Value = Visibility.Visible } + } } }; + SectionsContainer = new SettingsSectionsContainer + { + Masking = true, + RelativeSizeAxes = Axes.Both, + ExpandableHeader = CreateHeader(), + FixedHeader = searchTextBox = new SeekLimitedSearchTextBox + { + RelativeSizeAxes = Axes.X, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 0.95f, + Margin = new MarginPadding + { + Top = 20, + Bottom = 20 + }, + }, + Footer = CreateFooter() + }; + if (showSidebar) { AddInternal(Sidebar = new Sidebar { Width = sidebar_width }); - - SectionsContainer.SelectedSection.ValueChanged += section => - { - selectedSidebarButton.Selected = false; - selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); - selectedSidebarButton.Selected = true; - }; } - searchTextBox.Current.ValueChanged += term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue; - CreateSections()?.ForEach(AddSection); } + private void ensureContentLoaded() + { + if (SectionsContainer.LoadState > LoadState.NotLoaded) + return; + + Debug.Assert(SectionsContainer != null); + + LoadComponentAsync(SectionsContainer, d => + { + ContentContainer.Add(d); + d.FadeInFromZero(500); + loading.Hide(); + + if (Sidebar != null) + { + SectionsContainer.SelectedSection.ValueChanged += section => + { + selectedSidebarButton.Selected = false; + selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); + selectedSidebarButton.Selected = true; + }; + } + + searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true); + searchTextBox.TakeFocus(); + }); + } + protected void AddSection(SettingsSection section) { SectionsContainer.Add(section); @@ -136,6 +164,10 @@ namespace osu.Game.Overlays Section = section, Action = () => { + // may not be loaded yet. + if (SectionsContainer == null) + return; + SectionsContainer.ScrollTo(section); Sidebar.State = ExpandedState.Contracted; }, @@ -159,7 +191,8 @@ namespace osu.Game.Overlays { base.PopIn(); - ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); + ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint) + .OnComplete(_ => ensureContentLoaded()); Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); @@ -187,7 +220,7 @@ namespace osu.Game.Overlays protected override void OnFocus(FocusEvent e) { - searchTextBox.TakeFocus(); + searchTextBox?.TakeFocus(); base.OnFocus(e); } @@ -209,6 +242,8 @@ namespace osu.Game.Overlays { public SearchContainer SearchContainer; + public new ScheduledDelegate Schedule(Action action) => Scheduler.AddDelayed(action, TransformDelay); + protected override FlowContainer CreateScrollContentContainer() => SearchContainer = new SearchContainer { From 230c4eb2475a16c136d001598570d8b4d0c25450 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:47:27 +0900 Subject: [PATCH 354/961] Fade in sidebar buttons after the load has completed --- osu.Game/Overlays/Settings/SidebarButton.cs | 3 + osu.Game/Overlays/SettingsPanel.cs | 68 +++++++++++++-------- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index 30a53b351d..cf6a313a1f 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -22,6 +22,9 @@ namespace osu.Game.Overlays.Settings private readonly Box selectionIndicator; private readonly Container text; + // always consider as part of flow, even when not visible (for the sake of the initial animation). + public override bool IsPresent => true; + private SettingsSection section; public SettingsSection Section diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index c191f61e60..388c809be8 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -135,54 +135,70 @@ namespace osu.Game.Overlays LoadComponentAsync(SectionsContainer, d => { ContentContainer.Add(d); - d.FadeInFromZero(500); + d.FadeInFromZero(750, Easing.OutQuint); loading.Hide(); - if (Sidebar != null) - { - SectionsContainer.SelectedSection.ValueChanged += section => - { - selectedSidebarButton.Selected = false; - selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); - selectedSidebarButton.Selected = true; - }; - } - searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true); searchTextBox.TakeFocus(); + + if (Sidebar == null) + return; + + LoadComponentsAsync(createSidebarButtons(), buttons => + { + float delay = 0; + + foreach (var button in buttons) + { + Sidebar.Add(button); + + button.FadeOut() + .Delay(delay) + .FadeInFromZero(1000, Easing.OutQuint); + + delay += 30; + } + + SectionsContainer.SelectedSection.BindValueChanged(section => + { + if (selectedSidebarButton != null) + selectedSidebarButton.Selected = false; + + selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); + selectedSidebarButton.Selected = true; + }, true); + }); }); } - protected void AddSection(SettingsSection section) + private IEnumerable createSidebarButtons() { - SectionsContainer.Add(section); - - if (Sidebar != null) + foreach (var section in SectionsContainer) { - var button = new SidebarButton + yield return new SidebarButton { Section = section, Action = () => { - // may not be loaded yet. - if (SectionsContainer == null) + if (!SectionsContainer.IsLoaded) return; SectionsContainer.ScrollTo(section); Sidebar.State = ExpandedState.Contracted; }, }; - - Sidebar.Add(button); - - if (selectedSidebarButton == null) - { - selectedSidebarButton = Sidebar.Children.First(); - selectedSidebarButton.Selected = true; - } } } + protected void AddSection(SettingsSection section) + { + if (IsLoaded) + // just to keep things simple. can be accommodated for if we ever need it. + throw new InvalidOperationException("All sections must be added before the panel is loaded."); + + SectionsContainer.Add(section); + } + protected virtual Drawable CreateHeader() => new Container(); protected virtual Drawable CreateFooter() => new Container(); From e485728109869c1e3704056e1c2b9c98708c43d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:54:45 +0900 Subject: [PATCH 355/961] Add keywords to make finding audio offset adjustments easier in settings --- osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs index 7f2e377c83..eaa557bb37 100644 --- a/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Audio/OffsetSettings.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.Collections.Generic; +using System.Linq; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Localisation; @@ -13,6 +15,8 @@ namespace osu.Game.Overlays.Settings.Sections.Audio { protected override LocalisableString Header => "Offset Adjustment"; + public override IEnumerable FilterTerms => base.FilterTerms.Concat(new[] { "universal", "uo", "timing" }); + [BackgroundDependencyLoader] private void load(OsuConfigManager config) { From de61cb8e6a9a2fb22263098f6ec779360437adce Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 19:51:13 +0900 Subject: [PATCH 356/961] Adjust delay slightly --- osu.Game/Overlays/SettingsPanel.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 388c809be8..6593b6cb1e 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osuTK; using osuTK.Graphics; @@ -130,8 +129,6 @@ namespace osu.Game.Overlays if (SectionsContainer.LoadState > LoadState.NotLoaded) return; - Debug.Assert(SectionsContainer != null); - LoadComponentAsync(SectionsContainer, d => { ContentContainer.Add(d); @@ -207,8 +204,13 @@ namespace osu.Game.Overlays { base.PopIn(); - ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint) - .OnComplete(_ => ensureContentLoaded()); + ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint); + + // delay load enough to ensure it doesn't overlap with the initial animation. + // this is done as there is still a brief stutter during load completion which is more visible if the transition is in progress. + // the eventual goal would be to remove the need for this by splitting up load into smaller work pieces, or fixing the remaining + // load complete overheads. + Scheduler.AddDelayed(ensureContentLoaded, TRANSITION_LENGTH / 3); Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); From 1f942d15f825f6b5db0378e092fdc00c508f86b3 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 16 Aug 2021 13:38:57 +0200 Subject: [PATCH 357/961] Localise scoreboard --- .../BeatmapSet/Scores/NoScoresPlaceholder.cs | 7 +++--- .../Overlays/BeatmapSet/Scores/ScoreTable.cs | 23 ++++++++++--------- .../Scores/TopScoreStatisticsSection.cs | 22 ++++++++++-------- .../BeatmapSet/Scores/TopScoreUserSection.cs | 3 ++- .../Leaderboards/BeatmapLeaderboardScope.cs | 8 ++++--- 5 files changed, 35 insertions(+), 28 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs index 391ba93a4b..82ca3e030f 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/NoScoresPlaceholder.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Screens.Select.Leaderboards; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -30,15 +31,15 @@ namespace osu.Game.Overlays.BeatmapSet.Scores switch (scope) { default: - text.Text = @"No scores have been set yet. Maybe you can be the first!"; + text.Text = BeatmapsetsStrings.ShowScoreboardNoScoresGlobal; break; case BeatmapLeaderboardScope.Friend: - text.Text = @"None of your friends have set a score on this map yet."; + text.Text = BeatmapsetsStrings.ShowScoreboardNoScoresFriend; break; case BeatmapLeaderboardScope.Country: - text.Text = @"No one from your country has set a score on this map yet."; + text.Text = BeatmapsetsStrings.ShowScoreboardNoScoresCountry; break; } } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index fee0e62315..a154016824 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -20,6 +20,7 @@ using osuTK; using osuTK.Graphics; using osu.Framework.Localisation; using osu.Framework.Extensions.LocalisationExtensions; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet.Scores { @@ -93,13 +94,13 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { var columns = new List { - new TableColumn("rank", Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), + new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersRank, Anchor.CentreRight, new Dimension(GridSizeMode.AutoSize)), new TableColumn("", Anchor.Centre, new Dimension(GridSizeMode.Absolute, 70)), // grade - new TableColumn("score", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), - new TableColumn("accuracy", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)), + new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersScore, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), + new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, minSize: 60, maxSize: 70)), new TableColumn("", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 25)), // flag - new TableColumn("player", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)), - new TableColumn("max combo", Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120)) + new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersPlayer, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 125)), + new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersCombo, Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 70, maxSize: 120)) }; // All statistics across all scores, unordered. @@ -124,9 +125,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } if (showPerformancePoints) - columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30))); + columns.Add(new TableColumn(BeatmapsetsStrings.ShowScoreboardHeaderspp, Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30))); - columns.Add(new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize))); + columns.Add(new TableColumn(BeatmapsetsStrings.ShowScoreboardHeadersMods, Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize))); return columns.ToArray(); } @@ -140,7 +141,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { new OsuSpriteText { - Text = $"#{index + 1}", + Text = (index + 1).ToLocalisableString(@"\##"), Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, new UpdateableRank(score.Rank) @@ -168,7 +169,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores username, new OsuSpriteText { - Text = $@"{score.MaxCombo:N0}x", + Text = score.MaxCombo.ToLocalisableString(@"0\x"), Font = OsuFont.GetFont(size: text_size), Colour = score.MaxCombo == score.Beatmap?.MaxCombo ? highAccuracyColour : Color4.White } @@ -183,7 +184,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores content.Add(new OsuSpriteText { - Text = stat.MaxCount == null ? $"{stat.Count}" : $"{stat.Count}/{stat.MaxCount}", + Text = stat.MaxCount == null ? stat.Count.ToLocalisableString(@"N0") : (LocalisableString)$"{stat.Count}/{stat.MaxCount}", Font = OsuFont.GetFont(size: text_size), Colour = stat.Count == 0 ? Color4.Gray : Color4.White }); @@ -193,7 +194,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { content.Add(new OsuSpriteText { - Text = $@"{score.PP:N0}", + Text = score.PP.ToLocalisableString(@"N0"), Font = OsuFont.GetFont(size: text_size) }); } diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 3d5f3f595c..582528b675 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; @@ -13,6 +14,7 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Scoring; @@ -61,9 +63,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Spacing = new Vector2(margin, 0), Children = new Drawable[] { - totalScoreColumn = new TextColumn("total score", largeFont, top_columns_min_width), - accuracyColumn = new TextColumn("accuracy", largeFont, top_columns_min_width), - maxComboColumn = new TextColumn("max combo", largeFont, top_columns_min_width) + totalScoreColumn = new TextColumn(BeatmapsetsStrings.ShowScoreboardHeadersScoreTotal, largeFont, top_columns_min_width), + accuracyColumn = new TextColumn(BeatmapsetsStrings.ShowScoreboardHeadersAccuracy, largeFont, top_columns_min_width), + maxComboColumn = new TextColumn(BeatmapsetsStrings.ShowScoreboardHeadersCombo, largeFont, top_columns_min_width) } }, new FillFlowContainer @@ -81,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Direction = FillDirection.Horizontal, Spacing = new Vector2(margin, 0), }, - ppColumn = new TextColumn("pp", smallFont, bottom_columns_min_width), + ppColumn = new TextColumn(BeatmapsetsStrings.ShowScoreboardHeaderspp, smallFont, bottom_columns_min_width), modsColumn = new ModsInfoColumn(), } }, @@ -111,10 +113,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores score = value; accuracyColumn.Text = value.DisplayAccuracy; - maxComboColumn.Text = $@"{value.MaxCombo:N0}x"; + maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x"); ppColumn.Alpha = value.Beatmap?.Status.GrantsPerformancePoints() == true ? 1 : 0; - ppColumn.Text = $@"{value.PP:N0}"; + ppColumn.Text = value.PP.ToLocalisableString(@"N0"); statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn); modsColumn.Mods = value.Mods; @@ -126,7 +128,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private TextColumn createStatisticsColumn(HitResultDisplayStatistic stat) => new TextColumn(stat.DisplayName, smallFont, bottom_columns_min_width) { - Text = stat.MaxCount == null ? $"{stat.Count}" : $"{stat.Count}/{stat.MaxCount}" + Text = stat.MaxCount == null ? stat.Count.ToLocalisableString(@"N0") : (LocalisableString)$"{stat.Count}/{stat.MaxCount}" }; private class InfoColumn : CompositeDrawable @@ -134,7 +136,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly Box separator; private readonly OsuSpriteText text; - public InfoColumn(string title, Drawable content, float? minWidth = null) + public InfoColumn(LocalisableString title, Drawable content, float? minWidth = null) { AutoSizeAxes = Axes.Both; Margin = new MarginPadding { Vertical = 5 }; @@ -194,12 +196,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { private readonly SpriteText text; - public TextColumn(string title, FontUsage font, float? minWidth = null) + public TextColumn(LocalisableString title, FontUsage font, float? minWidth = null) : this(title, new OsuSpriteText { Font = font }, minWidth) { } - private TextColumn(string title, SpriteText text, float? minWidth = null) + private TextColumn(LocalisableString title, SpriteText text, float? minWidth = null) : base(title, text, minWidth) { this.text = text; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index 736366fb5c..c934020059 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -126,7 +127,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public int? ScorePosition { - set => rankText.Text = value == null ? "-" : $"#{value}"; + set => rankText.Text = value == null ? (LocalisableString)"-" : value.ToLocalisableString(@"\##"); } /// diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs index dc4c2ba4e2..5bcb4c27a7 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboardScope.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Select.Leaderboards { @@ -10,13 +12,13 @@ namespace osu.Game.Screens.Select.Leaderboards [Description("Local Ranking")] Local, - [Description("Country Ranking")] + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardCountry))] Country, - [Description("Global Ranking")] + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardGlobal))] Global, - [Description("Friend Ranking")] + [LocalisableDescription(typeof(BeatmapsetsStrings), nameof(BeatmapsetsStrings.ShowScoreboardFriend))] Friend, } } From 3325b0cc95d314e700a3e4d928fac9cf6b61c229 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 16 Aug 2021 14:50:08 +0200 Subject: [PATCH 358/961] Fix merge conflicts. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index dfba93cdbd..80dc185bb5 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.BeatmapSet set => this.value.Text = value; } - public Statistic(BeatmapStatisticsIconType icon, string name) + public Statistic(BeatmapStatisticsIconType icon, LocalisableString name) { TooltipText = name; RelativeSizeAxes = Axes.X; From 568d027013a67ddcc3ff58525001301cf353da8a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 22:07:41 +0900 Subject: [PATCH 359/961] Simplify weird conditionals --- .../Settings/Sections/Input/TabletSettings.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index 8303fee3ef..b8b86d9069 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -266,24 +266,16 @@ namespace osu.Game.Overlays.Settings.Sections.Input private void updateVisibility() { - if (!tabletHandler.Enabled.Value) - { - mainSettings.Hide(); - noTabletMessage.Hide(); - return; - } - - bool tabletFound = tablet.Value != null; - - if (!tabletFound) - { - mainSettings.Hide(); - noTabletMessage.Show(); - return; - } - - mainSettings.Show(); + mainSettings.Hide(); noTabletMessage.Hide(); + + if (!tabletHandler.Enabled.Value) + return; + + if (tablet.Value != null) + mainSettings.Show(); + else + noTabletMessage.Show(); } private void applyAspectRatio(BindableNumber sizeChanged) From 677f5aff9e39a0a2de16a0c25071f787db4a70e5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 23:30:50 +0900 Subject: [PATCH 360/961] Fix test failures --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index fa2c9ecdea..8632bfe681 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -32,6 +32,7 @@ namespace osu.Game.Tests.Visual.Settings [SetUpSteps] public void SetUpSteps() { + AddUntilStep("wait for load", () => panel.ChildrenOfType().Any()); AddStep("Scroll to top", () => panel.ChildrenOfType().First().ScrollToTop()); AddWaitStep("wait for scroll", 5); } From c3a86769323e11c637cd738393928be1e1499b47 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 16 Aug 2021 23:38:13 +0900 Subject: [PATCH 361/961] Simplify size specifications --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index c51f927f9f..508c8399b6 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -144,8 +144,7 @@ namespace osu.Game.Overlays.Changelog { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - Width = heart_size, - Height = heart_size, + Size = new Vector2(heart_size), Margin = new MarginPadding { Top = 70 }, Masking = true, EdgeEffect = new EdgeEffectParameters @@ -157,8 +156,7 @@ namespace osu.Game.Overlays.Changelog }, Child = new Sprite { - Width = heart_size, - Height = heart_size, + Size = new Vector2(heart_size), Texture = textures.Get(@"Online/supporter-heart"), }, }, From df6e4664e0aaa47788c1064be78126fe57fa1d75 Mon Sep 17 00:00:00 2001 From: emu1337 Date: Mon, 16 Aug 2021 16:42:07 +0200 Subject: [PATCH 362/961] changed history length in speed --- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index b1373cd215..5b8ec5103a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -29,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double max_speed_bonus = 45; // ~330BPM private const double speed_balancing_factor = 40; + protected override int HistoryLength => 32; + public Speed(Mod[] mods) : base(mods) { From 4bf22db4ff9ff21123d9a0cc35a6aa2ed099b65d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 00:23:30 +0900 Subject: [PATCH 363/961] Attempt to reduce skin lookup overhead where file access is not required --- osu.Game/Database/MutableDatabaseBackedStore.cs | 5 +++++ osu.Game/Skinning/SkinManager.cs | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Database/MutableDatabaseBackedStore.cs b/osu.Game/Database/MutableDatabaseBackedStore.cs index c9d0c4bc41..b0feb7bb78 100644 --- a/osu.Game/Database/MutableDatabaseBackedStore.cs +++ b/osu.Game/Database/MutableDatabaseBackedStore.cs @@ -36,6 +36,11 @@ namespace osu.Game.Database /// public IQueryable ConsumableItems => AddIncludesForConsumption(ContextFactory.Get().Set()); + /// + /// Access barebones items with no includes. + /// + public IQueryable Items => ContextFactory.Get().Set(); + /// /// Add a to the database. /// diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index ea55fd28c2..fca1670419 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -105,12 +105,12 @@ namespace osu.Game.Skinning /// Returns a list of all usable s that have been loaded by the user. /// /// A newly allocated list of available . - public List GetAllUserSkins() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList(); + public List GetAllUserSkins() => ModelStore.Items.Where(s => !s.DeletePending).ToList(); public void SelectRandomSkin() { // choose from only user skins, removing the current selection to ensure a new one is chosen. - var randomChoices = GetAllUsableSkins().Where(s => s.ID != CurrentSkinInfo.Value.ID).ToArray(); + var randomChoices = ModelStore.Items.Where(s => !s.DeletePending && s.ID != CurrentSkinInfo.Value.ID).ToArray(); if (randomChoices.Length == 0) { @@ -118,7 +118,8 @@ namespace osu.Game.Skinning return; } - CurrentSkinInfo.Value = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length)); + var chosen = randomChoices.ElementAt(RNG.Next(0, randomChoices.Length)); + CurrentSkinInfo.Value = ModelStore.ConsumableItems.Single(i => i.ID == chosen.ID); } protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name }; From 19cdd5c3234ad368f81d2c3df8f66abf63fb51df Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 15:25:35 +0000 Subject: [PATCH 364/961] recoded and added rhythm complexity calculator (untested) --- .../Difficulty/Skills/Speed.cs | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 5b8ec5103a..73704735d0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -20,6 +20,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double pi_over_4 = Math.PI / 4; private const double pi_over_2 = Math.PI / 2; + private const double rhythmMultiplier = 1.0; protected override double SkillMultiplier => 1400; protected override double StrainDecayBase => 0.3; protected override int ReducedSectionCount => 5; @@ -31,16 +32,91 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override int HistoryLength => 32; + private const int HistoryTimeMax = 4; // 4 seconds of calculatingRhythmBonus max. + public Speed(Mod[] mods) : base(mods) { } - private double calculateRhythmBonus(double time) + private bool isRatioEqual(double ratio, double a, double b) { - return 1.0; + return a + 15 > ratio * b && a - 15 < ratio * b; } + /// + /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . + /// + private double calculateRhythmBonus(double startTime) + { + // {doubles, triplets, quads, quints, 6-tuplets, 7 Tuplets, greater} + int previousIslandSize = -1; + double[] islandTimes = {0, 0, 0, 0, 0, 0, 0}; + int islandSize = 0; + + bool firstDeltaSwitch = false; + + for (int i = Previous.Count - 1; i < 0; i--) + { + double currDelta = ((OsuDifficultyHitObject)Previous[i - 1]).StrainTime; + double prevDelta = ((OsuDifficultyHitObject)Previous[i]).StrainTime; + double effectiveRatio = Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta); + + double currHistoricalDecay = Math.Max(0, (HistoryTimeMax - (startTime - Previous[i - 1].StartTime))) / HistoryTimeMax; + + // if (historyTime > HistoryTimeMax) + // break; // not sure if this even does what I want.. + + if (firstDeltaSwitch) + { + if (isRatioEqual(1.0, prevDelta, currDelta)) + { + islandSize++; // island is still progressing, count size. + } + + else + { + if (islandSize > 6) + islandSize = 6; + + if (Previous[i - 1].BaseObject is Slider) // bpm change is into slider, this is easy acc window + effectiveRatio *= 0.5; + + if (Previous[i].BaseObject is Slider) // bpm change was from a slider, this is easier typically than circle -> circle + effectiveRatio *= 0.75; + + if (previousIslandSize == islandSize) // repeated island size (ex: triplet -> triplet) + effectiveRatio *= 0.5; + + islandTimes[islandSize] = islandTimes[islandSize] + effectiveRatio * currHistoricalDecay; + + previousIslandSize = islandSize; // log the last island size. + + if (prevDelta * 1.25 < currDelta) // we're slowing down, stop counting + firstDeltaSwitch = false; // if we're speeding up, this stays true and we keep counting island size. + + islandSize = 0; + } + } + else if (prevDelta > 1.25 * currDelta) // we want to be speeding up. + { + // Begin counting island until we change speed again. + firstDeltaSwitch = true; + islandSize = 0; + } + } + + double rhythmComplexitySum = 0.0; + + for (int i = 0; i < islandTimes.Length; i++) + { + rhythmComplexitySum += islandTimes[i]; // sum the total amount of rhythm variance + } + +Console.WriteLine(Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); + + return Math.Min(1.5, Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); + } protected override double StrainValueOf(DifficultyHitObject current) { @@ -81,7 +157,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double GetPeakStrain(double time) { - return base.GetPeakStrain(time) * calculateRhythmBonus(time); + return base.GetPeakStrain(time);// * calculateRhythmBonus(current.StartTime); } } } From 7d46b3f9c5fe9062afa5528d025908173c5ca812 Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 16:06:50 +0000 Subject: [PATCH 365/961] initial testing and debugging --- .../Difficulty/Skills/Speed.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 73704735d0..433150a025 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -20,7 +20,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double pi_over_4 = Math.PI / 4; private const double pi_over_2 = Math.PI / 2; - private const double rhythmMultiplier = 1.0; + private const double rhythmMultiplier = 1.5; + protected override double SkillMultiplier => 1400; protected override double StrainDecayBase => 0.3; protected override int ReducedSectionCount => 5; @@ -32,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override int HistoryLength => 32; - private const int HistoryTimeMax = 4; // 4 seconds of calculatingRhythmBonus max. + private const int HistoryTimeMax = 3000; // 4 seconds of calculatingRhythmBonus max. public Speed(Mod[] mods) : base(mods) @@ -56,16 +57,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills bool firstDeltaSwitch = false; - for (int i = Previous.Count - 1; i < 0; i--) + for (int i = Previous.Count - 1; i > 0; i--) { double currDelta = ((OsuDifficultyHitObject)Previous[i - 1]).StrainTime; double prevDelta = ((OsuDifficultyHitObject)Previous[i]).StrainTime; double effectiveRatio = Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta); - double currHistoricalDecay = Math.Max(0, (HistoryTimeMax - (startTime - Previous[i - 1].StartTime))) / HistoryTimeMax; + if (effectiveRatio > 0.5) + effectiveRatio = 0.5 + (effectiveRatio - 0.5) * 5; // extra buff for 1/3 -> 1/4 etc transitions. - // if (historyTime > HistoryTimeMax) - // break; // not sure if this even does what I want.. + double currHistoricalDecay = Math.Max(0, (HistoryTimeMax - (startTime - Previous[i - 1].StartTime))) / HistoryTimeMax; if (firstDeltaSwitch) { @@ -113,9 +114,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills rhythmComplexitySum += islandTimes[i]; // sum the total amount of rhythm variance } -Console.WriteLine(Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); +// Console.WriteLine(Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); - return Math.Min(1.5, Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); + return Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2; } protected override double StrainValueOf(DifficultyHitObject current) From 78f9f4a23081ce994c702215ff94e6d805151b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Mon, 16 Aug 2021 20:36:46 +0200 Subject: [PATCH 366/961] Move time clamp to `Seek`/`transformSeekTo` methods --- osu.Game/Screens/Edit/EditorClock.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorClock.cs b/osu.Game/Screens/Edit/EditorClock.cs index 52c95088f3..ba83261731 100644 --- a/osu.Game/Screens/Edit/EditorClock.cs +++ b/osu.Game/Screens/Edit/EditorClock.cs @@ -118,7 +118,6 @@ namespace osu.Game.Screens.Edit if (!snapped || ControlPointInfo.TimingPoints.Count == 0) { - seekTime = Math.Clamp(seekTime, 0, TrackLength); SeekSmoothlyTo(seekTime); return; } @@ -151,8 +150,6 @@ namespace osu.Game.Screens.Edit if (seekTime < timingPoint.Time && timingPoint != ControlPointInfo.TimingPoints.First()) seekTime = timingPoint.Time; - // Ensure the sought point is within the boundaries - seekTime = Math.Clamp(seekTime, 0, TrackLength); SeekSmoothlyTo(seekTime); } @@ -191,6 +188,9 @@ namespace osu.Game.Screens.Edit seekingOrStopped.Value = IsSeeking = true; ClearTransforms(); + + // Ensure the sought point is within the boundaries + position = Math.Clamp(position, 0, TrackLength); return underlyingClock.Seek(position); } @@ -289,7 +289,7 @@ namespace osu.Game.Screens.Edit } private void transformSeekTo(double seek, double duration = 0, Easing easing = Easing.None) - => this.TransformTo(this.PopulateTransform(new TransformSeek(), seek, duration, easing)); + => this.TransformTo(this.PopulateTransform(new TransformSeek(), Math.Clamp(seek, 0, TrackLength), duration, easing)); private double currentTime { From 314c342841e23954c8fc3c80aa4a6930143a5fb6 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Mon, 16 Aug 2021 22:13:01 +0300 Subject: [PATCH 367/961] Avoid drawing segments of cursor trail near current cursor position --- osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 7a95111c91..43e0a57f7c 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -172,7 +172,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor float interval = partSize.X / 2.5f * IntervalMultiplier; - for (float d = interval; d < distance; d += interval) + for (float d = interval; d < distance - interval; d += interval) { lastPosition = pos1 + direction * d; addPart(lastPosition.Value); From ef367c6547f7dc27ad7fc9c2470f1403438a1cde Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Mon, 16 Aug 2021 22:52:19 +0300 Subject: [PATCH 368/961] Move implementation to be legacy only --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs | 1 + osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs index 587ff4b573..75d847d54d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyCursorTrail.cs @@ -62,6 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy protected override bool InterpolateMovements => !disjointTrail; protected override float IntervalMultiplier => 1 / Math.Max(cursorSize.Value, 1); + protected override bool AvoidDrawingNearCursor => !disjointTrail; protected override void Update() { diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs index 43e0a57f7c..62cab4d6d7 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/CursorTrail.cs @@ -138,6 +138,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected virtual bool InterpolateMovements => true; protected virtual float IntervalMultiplier => 1.0f; + protected virtual bool AvoidDrawingNearCursor => false; private Vector2? lastPosition; private readonly InputResampler resampler = new InputResampler(); @@ -171,8 +172,9 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor Vector2 direction = diff / distance; float interval = partSize.X / 2.5f * IntervalMultiplier; + float stopAt = distance - (AvoidDrawingNearCursor ? interval : 0); - for (float d = interval; d < distance - interval; d += interval) + for (float d = interval; d < stopAt; d += interval) { lastPosition = pos1 + direction * d; addPart(lastPosition.Value); From 176b3e75335476273ceb305a60c2b4a0fc9fa3f4 Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 22:14:29 +0000 Subject: [PATCH 369/961] changed decay system to allow for customizing the currentStrain --- .../Difficulty/Skills/Movement.cs | 2 +- .../Difficulty/Skills/Strain.cs | 4 +- .../Difficulty/Skills/Aim.cs | 2 +- .../Difficulty/Skills/OsuStrainSkill.cs | 4 +- .../Difficulty/Skills/Speed.cs | 11 +--- .../Difficulty/Skills/Colour.cs | 2 +- .../Difficulty/Skills/Rhythm.cs | 2 +- .../Difficulty/Skills/Stamina.cs | 2 +- .../Difficulty/Skills/StrainDecaySkill.cs | 64 +++++++++++++++++++ .../Rulesets/Difficulty/Skills/StrainSkill.cs | 44 +++---------- 10 files changed, 83 insertions(+), 54 deletions(-) create mode 100644 osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs index 4372ed938c..cfb3fe40be 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs @@ -9,7 +9,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Catch.Difficulty.Skills { - public class Movement : StrainSkill + public class Movement : StrainDecaySkill { private const float absolute_player_positioning_error = 16f; private const float normalized_hitobject_radius = 41.0f; diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index 2ba2ee6b4a..01d930d585 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -10,7 +10,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.Mania.Difficulty.Skills { - public class Strain : StrainSkill + public class Strain : StrainDecaySkill { private const double individual_decay_base = 0.125; private const double overall_decay_base = 0.30; @@ -71,7 +71,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills return individualStrain + overallStrain - CurrentStrain; } - protected override double GetPeakStrain(double offset) + protected override double CalculateInitialStrain(double offset) => applyDecay(individualStrain, offset - Previous[0].StartTime, individual_decay_base) + applyDecay(overallStrain, offset - Previous[0].StartTime, overall_decay_base); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 16a18cbcb9..f08c19af76 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : OsuStrainSkill + public class Aim : OsuStrainDecaySkill { private const double angle_bonus_begin = Math.PI / 3; private const double timing_threshold = 107; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index e47edc37cc..c1bee9b202 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -10,7 +10,7 @@ using osu.Framework.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { - public abstract class OsuStrainSkill : StrainSkill + public abstract class OsuStrainDecaySkill : StrainDecaySkill { /// /// The number of sections with the highest strains, which the peak strain reductions will apply to. @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// protected virtual double DifficultyMultiplier => 1.06; - protected OsuStrainSkill(Mod[] mods) + protected OsuStrainDecaySkill(Mod[] mods) : base(mods) { } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 433150a025..bb40ff657a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit. /// - public class Speed : OsuStrainSkill + public class Speed : OsuStrainDecaySkill { private const double single_spacing_threshold = 125; @@ -151,14 +151,5 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return (1 + (speedBonus - 1) * 0.75) * angleBonus * (0.95 + speedBonus * Math.Pow(distance / single_spacing_threshold, 3.5)) / osuCurrent.StrainTime; } - protected override double GetTotalCurrentStrain(DifficultyHitObject current) - { - return base.GetTotalCurrentStrain(current) * calculateRhythmBonus(current.StartTime); - } - - protected override double GetPeakStrain(double time) - { - return base.GetPeakStrain(time);// * calculateRhythmBonus(current.StartTime); - } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs index 769d021362..0c17ca66b9 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Colour.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// /// Calculates the colour coefficient of taiko difficulty. /// - public class Colour : StrainSkill + public class Colour : StrainDecaySkill { protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs index a32f6ebe0d..973e55f4b4 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Rhythm.cs @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// /// Calculates the rhythm coefficient of taiko difficulty. /// - public class Rhythm : StrainSkill + public class Rhythm : StrainDecaySkill { protected override double SkillMultiplier => 10; protected override double StrainDecayBase => 0; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 4cceadb23f..54cf233d69 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills /// /// The reference play style chosen uses two hands, with full alternating (the hand changes after every hit). /// - public class Stamina : StrainSkill + public class Stamina : StrainDecaySkill { protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.4; diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs new file mode 100644 index 0000000000..dab1081abb --- /dev/null +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs @@ -0,0 +1,64 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Rulesets.Difficulty.Skills +{ + /// + /// Used to processes strain values of s, keep track of strain levels caused by the processed objects + /// and to calculate a final difficulty value representing the difficulty of hitting all the processed objects. + /// + public abstract class StrainDecaySkill : StrainSkill + { + /// + /// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other. + /// + protected abstract double SkillMultiplier { get; } + + /// + /// Determines how quickly strain decays for the given skill. + /// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second. + /// + protected abstract double StrainDecayBase { get; } + + /// + /// The current strain level. + /// + protected double CurrentStrain { get; private set; } = 1; + + protected StrainDecaySkill(Mod[] mods) + : base(mods) + { + } + + /// + /// Retrieves the peak strain at a point in time. + /// + /// The time to retrieve the peak strain at. + /// The peak strain. + protected override double CalculateInitialStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime); + + /// + /// Returns the strain value of . This value is calculated with or without respect to previous objects. + /// + protected override double StrainValueAt(DifficultyHitObject current) + { + CurrentStrain *= strainDecay(current.DeltaTime); + CurrentStrain += StrainValueOf(current) * SkillMultiplier; + + return CurrentStrain; + } + + /// + /// Calculates the strain value of a . This value is affected by previously processed objects. + /// + protected abstract double StrainValueOf(DifficultyHitObject current); + + private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000); + } +} diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index 95b0fe43fc..e8ae452506 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -15,27 +15,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills /// public abstract class StrainSkill : Skill { - /// - /// Strain values are multiplied by this number for the given skill. Used to balance the value of different skills between each other. - /// - protected abstract double SkillMultiplier { get; } - - /// - /// Determines how quickly strain decays for the given skill. - /// For example a value of 0.15 indicates that strain decays to 15% of its original value in one second. - /// - protected abstract double StrainDecayBase { get; } - /// /// The weight by which each strain value decays. /// protected virtual double DecayWeight => 0.9; - /// - /// The current strain level. - /// - protected double CurrentStrain { get; private set; } = 1; - /// /// The length of each strain section. /// @@ -52,6 +36,11 @@ namespace osu.Game.Rulesets.Difficulty.Skills { } + /// + /// Returns the strain value of . This value is calculated with or without respect to previous objects. + /// + protected abstract double StrainValueAt(DifficultyHitObject current); + /// /// Process a and update current strain values accordingly. /// @@ -68,15 +57,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills currentSectionEnd += SectionLength; } - CurrentStrain *= strainDecay(current.DeltaTime); - CurrentStrain += StrainValueOf(current) * SkillMultiplier; - - currentSectionPeak = Math.Max(GetTotalCurrentStrain(current), currentSectionPeak); - } - - protected virtual double GetTotalCurrentStrain(DifficultyHitObject current) - { - return CurrentStrain; + currentSectionPeak = Math.Max(StrainValueAt(current), currentSectionPeak); } /// @@ -93,9 +74,9 @@ namespace osu.Game.Rulesets.Difficulty.Skills /// The beginning of the new section in milliseconds. private void startNewSectionFrom(double time) { - // The maximum strain of the new section is not zero by default, strain decays as usual regardless of section boundaries. + // The maximum strain of the new section is not zero by default // This means we need to capture the strain level at the beginning of the new section, and use that as the initial peak level. - currentSectionPeak = GetPeakStrain(time); + currentSectionPeak = CalculateInitialStrain(time); } /// @@ -103,7 +84,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills /// /// The time to retrieve the peak strain at. /// The peak strain. - protected virtual double GetPeakStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime); + protected abstract double CalculateInitialStrain(double time); /// /// Returns a live enumerable of the peak strains for each section of the beatmap, @@ -129,12 +110,5 @@ namespace osu.Game.Rulesets.Difficulty.Skills return difficulty; } - - /// - /// Calculates the strain value of a . This value is affected by previously processed objects. - /// - protected abstract double StrainValueOf(DifficultyHitObject current); - - private double strainDecay(double ms) => Math.Pow(StrainDecayBase, ms / 1000); } } From 5561e4852e838c226257d09088e3f51e42d6f2d2 Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 22:23:40 +0000 Subject: [PATCH 370/961] removed stuff --- .../Difficulty/Skills/Speed.cs | 85 ------------------- 1 file changed, 85 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index bb40ff657a..78d1438923 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -20,8 +20,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double pi_over_4 = Math.PI / 4; private const double pi_over_2 = Math.PI / 2; - private const double rhythmMultiplier = 1.5; - protected override double SkillMultiplier => 1400; protected override double StrainDecayBase => 0.3; protected override int ReducedSectionCount => 5; @@ -31,94 +29,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private const double max_speed_bonus = 45; // ~330BPM private const double speed_balancing_factor = 40; - protected override int HistoryLength => 32; - - private const int HistoryTimeMax = 3000; // 4 seconds of calculatingRhythmBonus max. - public Speed(Mod[] mods) : base(mods) { } - private bool isRatioEqual(double ratio, double a, double b) - { - return a + 15 > ratio * b && a - 15 < ratio * b; - } - - /// - /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . - /// - private double calculateRhythmBonus(double startTime) - { - // {doubles, triplets, quads, quints, 6-tuplets, 7 Tuplets, greater} - int previousIslandSize = -1; - double[] islandTimes = {0, 0, 0, 0, 0, 0, 0}; - int islandSize = 0; - - bool firstDeltaSwitch = false; - - for (int i = Previous.Count - 1; i > 0; i--) - { - double currDelta = ((OsuDifficultyHitObject)Previous[i - 1]).StrainTime; - double prevDelta = ((OsuDifficultyHitObject)Previous[i]).StrainTime; - double effectiveRatio = Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta); - - if (effectiveRatio > 0.5) - effectiveRatio = 0.5 + (effectiveRatio - 0.5) * 5; // extra buff for 1/3 -> 1/4 etc transitions. - - double currHistoricalDecay = Math.Max(0, (HistoryTimeMax - (startTime - Previous[i - 1].StartTime))) / HistoryTimeMax; - - if (firstDeltaSwitch) - { - if (isRatioEqual(1.0, prevDelta, currDelta)) - { - islandSize++; // island is still progressing, count size. - } - - else - { - if (islandSize > 6) - islandSize = 6; - - if (Previous[i - 1].BaseObject is Slider) // bpm change is into slider, this is easy acc window - effectiveRatio *= 0.5; - - if (Previous[i].BaseObject is Slider) // bpm change was from a slider, this is easier typically than circle -> circle - effectiveRatio *= 0.75; - - if (previousIslandSize == islandSize) // repeated island size (ex: triplet -> triplet) - effectiveRatio *= 0.5; - - islandTimes[islandSize] = islandTimes[islandSize] + effectiveRatio * currHistoricalDecay; - - previousIslandSize = islandSize; // log the last island size. - - if (prevDelta * 1.25 < currDelta) // we're slowing down, stop counting - firstDeltaSwitch = false; // if we're speeding up, this stays true and we keep counting island size. - - islandSize = 0; - } - } - else if (prevDelta > 1.25 * currDelta) // we want to be speeding up. - { - // Begin counting island until we change speed again. - firstDeltaSwitch = true; - islandSize = 0; - } - } - - double rhythmComplexitySum = 0.0; - - for (int i = 0; i < islandTimes.Length; i++) - { - rhythmComplexitySum += islandTimes[i]; // sum the total amount of rhythm variance - } - -// Console.WriteLine(Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2); - - return Math.Sqrt(4 + rhythmComplexitySum * rhythmMultiplier) / 2; - } - protected override double StrainValueOf(DifficultyHitObject current) { if (current.BaseObject is Spinner) From 61045bd0876afac630c9611de1398c0c65677141 Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 22:36:14 +0000 Subject: [PATCH 371/961] adjusted code comments --- osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs | 8 -------- osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs index dab1081abb..dbac132faf 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs @@ -36,16 +36,8 @@ namespace osu.Game.Rulesets.Difficulty.Skills { } - /// - /// Retrieves the peak strain at a point in time. - /// - /// The time to retrieve the peak strain at. - /// The peak strain. protected override double CalculateInitialStrain(double time) => CurrentStrain * strainDecay(time - Previous[0].StartTime); - /// - /// Returns the strain value of . This value is calculated with or without respect to previous objects. - /// protected override double StrainValueAt(DifficultyHitObject current) { CurrentStrain *= strainDecay(current.DeltaTime); diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index e8ae452506..0880f1b08e 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Difficulty.Skills } /// - /// Returns the strain value of . This value is calculated with or without respect to previous objects. + /// Returns the strain value at . This value is calculated with or without respect to previous objects. /// protected abstract double StrainValueAt(DifficultyHitObject current); From 9b21016eed1aadc232c0023b23624d61775659c3 Mon Sep 17 00:00:00 2001 From: Xexxar Date: Mon, 16 Aug 2021 22:46:56 +0000 Subject: [PATCH 372/961] accidently renamed osuStrainSkill, fixed --- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs | 4 ++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index f08c19af76..16a18cbcb9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to correctly aim at every object in the map with a uniform CircleSize and normalized distances. /// - public class Aim : OsuStrainDecaySkill + public class Aim : OsuStrainSkill { private const double angle_bonus_begin = Math.PI / 3; private const double timing_threshold = 107; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs index c1bee9b202..7bcd867a9c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/OsuStrainSkill.cs @@ -10,7 +10,7 @@ using osu.Framework.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { - public abstract class OsuStrainDecaySkill : StrainDecaySkill + public abstract class OsuStrainSkill : StrainDecaySkill { /// /// The number of sections with the highest strains, which the peak strain reductions will apply to. @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// protected virtual double DifficultyMultiplier => 1.06; - protected OsuStrainDecaySkill(Mod[] mods) + protected OsuStrainSkill(Mod[] mods) : base(mods) { } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 78d1438923..f0eb199e5f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// /// Represents the skill required to press keys with regards to keeping up with the speed at which objects need to be hit. /// - public class Speed : OsuStrainDecaySkill + public class Speed : OsuStrainSkill { private const double single_spacing_threshold = 125; From 97d5b80834568d76ca423cf876aaf9955681a72f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:18:21 +0900 Subject: [PATCH 373/961] Fix joining with incorrect password --- .../Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index 2d94b2328d..776307e20e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private MultiplayerClient multiplayerClient { get; set; } public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - => base.CreateRoom(room, r => joinMultiplayerRoom(r, r.Password.Value, onSuccess, onError), onError); + => base.CreateRoom(room, r => joinMultiplayerRoom(r, room.Password.Value, onSuccess, onError), onError); public override void JoinRoom(Room room, string password = null, Action onSuccess = null, Action onError = null) { From 352949069a4a3130c8db14ea8412ac11c93d57aa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:36:43 +0900 Subject: [PATCH 374/961] Move filter to LoungeSubScreen --- .../TestSceneLoungeRoomsContainer.cs | 10 ++++----- .../Multiplayer/TestSceneMultiplayer.cs | 22 +++++++++++-------- .../Components/ListingPollingComponent.cs | 10 +++++---- .../Lounge/Components/RoomsContainer.cs | 9 ++++---- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 15 ++++++------- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 4 ---- ...stRequestHandlingMultiplayerRoomManager.cs | 5 ----- .../IOnlinePlayTestSceneDependencies.cs | 6 ----- .../Visual/OnlinePlay/OnlinePlayTestScene.cs | 2 -- .../OnlinePlayTestSceneDependencies.cs | 4 ---- 10 files changed, 35 insertions(+), 52 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index f3d961a646..7e822f898e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -115,11 +115,11 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4); - AddStep("filter one room", () => container.Filter(new FilterCriteria { SearchString = "1" })); + AddStep("filter one room", () => container.Filter.Value = new FilterCriteria { SearchString = "1" }); AddUntilStep("1 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 1); - AddStep("remove filter", () => container.Filter(null)); + AddStep("remove filter", () => container.Filter.Value = null); AddUntilStep("4 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 4); } @@ -131,13 +131,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add rooms", () => RoomManager.AddRooms(3, new CatchRuleset().RulesetInfo)); // Todo: What even is this case...? - AddStep("set empty filter criteria", () => container.Filter(null)); + AddStep("set empty filter criteria", () => container.Filter.Value = null); AddUntilStep("5 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 5); - AddStep("filter osu! rooms", () => container.Filter(new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo })); + AddStep("filter osu! rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new OsuRuleset().RulesetInfo }); AddUntilStep("2 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 2); - AddStep("filter catch rooms", () => container.Filter(new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo })); + AddStep("filter catch rooms", () => container.Filter.Value = new FilterCriteria { Ruleset = new CatchRuleset().RulesetInfo }); AddUntilStep("3 rooms visible", () => container.Rooms.Count(r => r.IsPresent) == 3); } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 08b3fb98a8..cf2f2f259e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -132,11 +132,9 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestExitMidJoin() { - Room room = null; - AddStep("create room", () => { - room = new Room + multiplayerScreen.RoomManager.AddRoom(new Room { Name = { Value = "Test Room" }, Playlist = @@ -147,14 +145,16 @@ namespace osu.Game.Tests.Visual.Multiplayer Ruleset = { Value = new OsuRuleset().RulesetInfo }, } } - }; + }); }); - AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria()); + AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); + AddUntilStep("wait for room", () => this.ChildrenOfType().Any()); + AddStep("select room", () => InputManager.Key(Key.Down)); - AddStep("join room and immediately exit", () => + AddStep("join room and immediately exit select", () => { - multiplayerScreen.ChildrenOfType().Single().Open(room); + InputManager.Key(Key.Enter); Schedule(() => Stack.CurrentScreen.Exit()); }); } @@ -178,7 +178,9 @@ namespace osu.Game.Tests.Visual.Multiplayer }); }); - AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria()); + AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); + AddUntilStep("wait for room", () => this.ChildrenOfType().Any()); + AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("join room", () => InputManager.Key(Key.Enter)); @@ -226,7 +228,9 @@ namespace osu.Game.Tests.Visual.Multiplayer }); }); - AddStep("refresh rooms", () => multiplayerScreen.RoomManager.Filter.Value = new FilterCriteria()); + AddStep("refresh rooms", () => this.ChildrenOfType().Single().UpdateFilter()); + AddUntilStep("wait for room", () => this.ChildrenOfType().Any()); + AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("join room", () => InputManager.Key(Key.Enter)); diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index bc6480d05e..1387b5a671 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -18,8 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Components public IBindable InitialRoomsReceived => initialRoomsReceived; private readonly Bindable initialRoomsReceived = new Bindable(); - [Resolved] - private Bindable currentFilter { get; set; } + public readonly Bindable Filter = new Bindable(); [Resolved] private Bindable selectedRoom { get; set; } @@ -27,7 +26,7 @@ namespace osu.Game.Screens.OnlinePlay.Components [BackgroundDependencyLoader] private void load() { - currentFilter.BindValueChanged(_ => + Filter.BindValueChanged(_ => { RoomManager.ClearRooms(); initialRoomsReceived.Value = false; @@ -44,10 +43,13 @@ namespace osu.Game.Screens.OnlinePlay.Components if (!API.IsLoggedIn) return base.Poll(); + if (Filter.Value == null) + return base.Poll(); + var tcs = new TaskCompletionSource(); pollReq?.Cancel(); - pollReq = new GetRoomsRequest(currentFilter.Value.Status, currentFilter.Value.Category); + pollReq = new GetRoomsRequest(Filter.Value.Status, Filter.Value.Category); pollReq.Success += result => { diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 46d9850fde..e243477a8c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -30,8 +30,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components public IReadOnlyList Rooms => roomFlow.FlowingChildren.Cast().ToArray(); - [Resolved(CanBeNull = true)] - private Bindable filter { get; set; } + public readonly Bindable Filter = new Bindable(); [Resolved] private Bindable selectedRoom { get; set; } @@ -74,7 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components rooms.BindTo(roomManager.Rooms); - filter?.BindValueChanged(criteria => Filter(criteria.NewValue)); + Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true); selectedRoom.BindValueChanged(selection => { @@ -85,7 +84,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void updateSelection() => roomFlow.Children.ForEach(r => r.State = r.Room == selectedRoom.Value ? SelectionState.Selected : SelectionState.NotSelected); - public void Filter(FilterCriteria criteria) + private void applyFilterCriteria(FilterCriteria criteria) { roomFlow.Children.ForEach(r => { @@ -126,7 +125,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomFlow.Add(new DrawableRoom(room)); } - Filter(filter?.Value); + applyFilterCriteria(Filter?.Value); updateSelection(); } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index bd2648791c..3e8d07d002 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -56,9 +56,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [Resolved(CanBeNull = true)] private OngoingOperationTracker ongoingOperationTracker { get; set; } - [Resolved(CanBeNull = true)] - private Bindable filter { get; set; } - [Resolved] private IBindable ruleset { get; set; } @@ -68,6 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [CanBeNull] private LeasedBindable selectionLease; + private readonly Bindable filter = new Bindable(new FilterCriteria()); private readonly IBindable operationInProgress = new Bindable(); private readonly IBindable isIdle = new BindableBool(); private LoadingLayer loadingLayer; @@ -81,13 +79,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); - filter ??= new Bindable(new FilterCriteria()); - OsuScrollContainer scrollContainer; InternalChildren = new Drawable[] { - ListingPollingComponent = CreatePollingComponent(), + ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter), loadingLayer = new LoadingLayer(true), new Container { @@ -161,7 +157,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { RelativeSizeAxes = Axes.Both, ScrollbarOverlapsContent = false, - Child = roomsContainer = new RoomsContainer() + Child = roomsContainer = new RoomsContainer + { + Filter = { BindTarget = filter } + } }, } }, @@ -202,7 +201,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge #region Filtering - protected void UpdateFilter() => Scheduler.AddOnce(updateFilter); + public void UpdateFilter() => Scheduler.AddOnce(updateFilter); private ScheduledDelegate scheduledFilterUpdate; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 183b7e51f9..e5962db608 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -20,7 +20,6 @@ using osu.Game.Overlays; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Users; using osuTK; using osuTK.Graphics; @@ -49,9 +48,6 @@ namespace osu.Game.Screens.OnlinePlay [Cached] private readonly Bindable selectedRoom = new Bindable(); - [Cached] - private readonly Bindable currentFilter = new Bindable(new FilterCriteria()); - [Cached] private readonly OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker(); diff --git a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs index 2e56c8a094..31b59be61e 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs @@ -5,14 +5,12 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Multiplayer; namespace osu.Game.Tests.Visual.Multiplayer @@ -32,9 +30,6 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private OsuGameBase game { get; set; } - [Cached] - public readonly Bindable Filter = new Bindable(new FilterCriteria()); - public new readonly List Rooms = new List(); private int currentRoomId; diff --git a/osu.Game/Tests/Visual/OnlinePlay/IOnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/IOnlinePlayTestSceneDependencies.cs index 6e1e831d9b..71acefb158 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/IOnlinePlayTestSceneDependencies.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/IOnlinePlayTestSceneDependencies.cs @@ -4,7 +4,6 @@ using osu.Framework.Bindables; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -23,11 +22,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay /// IRoomManager RoomManager { get; } - /// - /// The cached . - /// - Bindable Filter { get; } - /// /// The cached . /// diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index 997c910dd4..8716646074 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -20,7 +19,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay { public Bindable SelectedRoom => OnlinePlayDependencies?.SelectedRoom; public IRoomManager RoomManager => OnlinePlayDependencies?.RoomManager; - public Bindable Filter => OnlinePlayDependencies?.Filter; public OngoingOperationTracker OngoingOperationTracker => OnlinePlayDependencies?.OngoingOperationTracker; public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker => OnlinePlayDependencies?.AvailabilityTracker; diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs index 05ba509a73..e39711b7ce 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs @@ -9,7 +9,6 @@ using osu.Framework.Graphics; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.OnlinePlay.Lounge.Components; namespace osu.Game.Tests.Visual.OnlinePlay { @@ -20,7 +19,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay { public Bindable SelectedRoom { get; } public IRoomManager RoomManager { get; } - public Bindable Filter { get; } public OngoingOperationTracker OngoingOperationTracker { get; } public OnlinePlayBeatmapAvailabilityTracker AvailabilityTracker { get; } @@ -36,7 +34,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay { SelectedRoom = new Bindable(); RoomManager = CreateRoomManager(); - Filter = new Bindable(new FilterCriteria()); OngoingOperationTracker = new OngoingOperationTracker(); AvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker(); @@ -44,7 +41,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay CacheAs(SelectedRoom); CacheAs(RoomManager); - CacheAs(Filter); CacheAs(OngoingOperationTracker); CacheAs(AvailabilityTracker); CacheAs(new OverlayColourProvider(OverlayColourScheme.Plum)); From c4a42c4db007af794104c65c8c768506eb4f5b12 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:36:59 +0900 Subject: [PATCH 375/961] Fix BasicTestRoomManager overriding rooms --- .../Tests/Visual/OnlinePlay/BasicTestRoomManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs index d7c5a0a0e4..55fbb9f1a6 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs @@ -28,6 +28,8 @@ namespace osu.Game.Tests.Visual.OnlinePlay IBindableList IRoomManager.Rooms => Rooms; + private int currentRoomId; + public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) { room.RoomID.Value ??= Rooms.Select(r => r.RoomID.Value).Where(id => id != null).Select(id => id.Value).DefaultIfEmpty().Max() + 1; @@ -76,9 +78,9 @@ namespace osu.Game.Tests.Visual.OnlinePlay { var room = new Room { - RoomID = { Value = i }, - Position = { Value = i }, - Name = { Value = $"Room {i}" }, + RoomID = { Value = currentRoomId }, + Position = { Value = currentRoomId }, + Name = { Value = $"Room {currentRoomId}" }, Host = { Value = new User { Username = "Host" } }, EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }, Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal }, @@ -101,6 +103,8 @@ namespace osu.Game.Tests.Visual.OnlinePlay } CreateRoom(room); + + currentRoomId++; } } } From 1e282432c90397d976164da3f9e03b99876199da Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:40:25 +0900 Subject: [PATCH 376/961] Fix password in a better way --- osu.Game/Screens/OnlinePlay/Components/RoomManager.cs | 3 ++- .../Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs index 43bf3a2ce5..3b6c1c8be0 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomManager.cs @@ -60,7 +60,8 @@ namespace osu.Game.Screens.OnlinePlay.Components AddOrUpdateRoom(result); room.CopyFrom(result); // Also copy back to the source model, since this is likely to have been stored elsewhere. - onSuccess?.Invoke(result); + // The server may not contain all properties (such as password), so invoke success with the given room. + onSuccess?.Invoke(room); }; req.Failure += exception => diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs index 776307e20e..2d94b2328d 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs @@ -19,7 +19,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private MultiplayerClient multiplayerClient { get; set; } public override void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - => base.CreateRoom(room, r => joinMultiplayerRoom(r, room.Password.Value, onSuccess, onError), onError); + => base.CreateRoom(room, r => joinMultiplayerRoom(r, r.Password.Value, onSuccess, onError), onError); public override void JoinRoom(Room room, string password = null, Action onSuccess = null, Action onError = null) { From b672d4b9366d0a695b8085b649c91c037b59878f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:42:17 +0900 Subject: [PATCH 377/961] Refactor RequestHandlingMultiplayerRoomManager to avoid confusion --- .../Multiplayer/TestSceneMultiplayer.cs | 6 +++--- .../Multiplayer/TestMultiplayerClient.cs | 4 ++-- ...stRequestHandlingMultiplayerRoomManager.cs | 20 +++++++------------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index cf2f2f259e..8b96f5dc80 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -134,7 +134,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddRoom(new Room + multiplayerScreen.RoomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Playlist = @@ -164,7 +164,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddRoom(new Room + multiplayerScreen.RoomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Playlist = @@ -213,7 +213,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddRoom(new Room + multiplayerScreen.RoomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Password = { Value = "password" }, diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs index f2da66d666..2c0ca0b872 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs @@ -127,7 +127,7 @@ namespace osu.Game.Tests.Visual.Multiplayer protected override Task JoinRoom(long roomId, string? password = null) { - var apiRoom = roomManager.Rooms.Single(r => r.RoomID.Value == roomId); + var apiRoom = roomManager.ServerSideRooms.Single(r => r.RoomID.Value == roomId); if (password != apiRoom.Password.Value) throw new InvalidOperationException("Invalid password."); @@ -260,7 +260,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Debug.Assert(Room != null); - var apiRoom = roomManager.Rooms.Single(r => r.RoomID.Value == Room.RoomID); + var apiRoom = roomManager.ServerSideRooms.Single(r => r.RoomID.Value == Room.RoomID); var set = apiRoom.Playlist.FirstOrDefault(p => p.BeatmapID == beatmapId)?.Beatmap.Value.BeatmapSet ?? beatmaps.QueryBeatmap(b => b.OnlineBeatmapID == beatmapId)?.BeatmapSet; diff --git a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs index 31b59be61e..41102ae7b5 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private OsuGameBase game { get; set; } - public new readonly List Rooms = new List(); + public readonly List ServerSideRooms = new List(); private int currentRoomId; private int currentPlaylistItemId; @@ -55,7 +55,7 @@ namespace osu.Game.Tests.Visual.Multiplayer apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value); apiRoom.Password.Value = createRoomRequest.Room.Password.Value; - AddRoom(apiRoom); + AddServerSideRoom(apiRoom); var responseRoom = new APICreatedRoom(); responseRoom.CopyFrom(createResponseRoom(apiRoom, false)); @@ -65,7 +65,7 @@ namespace osu.Game.Tests.Visual.Multiplayer case JoinRoomRequest joinRoomRequest: { - var room = Rooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value); + var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value); if (joinRoomRequest.Password != room.Password.Value) { @@ -84,14 +84,14 @@ namespace osu.Game.Tests.Visual.Multiplayer case GetRoomsRequest getRoomsRequest: var roomsWithoutParticipants = new List(); - foreach (var r in Rooms) + foreach (var r in ServerSideRooms) roomsWithoutParticipants.Add(createResponseRoom(r, false)); getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); return true; case GetRoomRequest getRoomRequest: - getRoomRequest.TriggerSuccess(createResponseRoom(Rooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true)); + getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true)); return true; case GetBeatmapSetRequest getBeatmapSetRequest: @@ -127,17 +127,15 @@ namespace osu.Game.Tests.Visual.Multiplayer }; } - public void AddRoom(Room room) + public void AddServerSideRoom(Room room) { room.RoomID.Value ??= currentRoomId++; for (int i = 0; i < room.Playlist.Count; i++) room.Playlist[i].ID = currentPlaylistItemId++; - Rooms.Add(room); + ServerSideRooms.Add(room); } - public new void RemoveRoom(Room room) => base.RemoveRoom(room); - private Room createResponseRoom(Room room, bool withParticipants) { var responseRoom = new Room(); @@ -147,9 +145,5 @@ namespace osu.Game.Tests.Visual.Multiplayer responseRoom.RecentParticipants.Clear(); return responseRoom; } - - public new void ClearRooms() => base.ClearRooms(); - - public new void Schedule(Action action) => base.Schedule(action); } } From 5214731dc1be8fdfe638143386319377ad839f54 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:45:10 +0900 Subject: [PATCH 378/961] Refactor test a bit --- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 8b96f5dc80..e618b28f40 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -44,6 +44,8 @@ namespace osu.Game.Tests.Visual.Multiplayer private TestMultiplayer multiplayerScreen; private TestMultiplayerClient client; + private TestRequestHandlingMultiplayerRoomManager roomManager => multiplayerScreen.RoomManager; + [Cached(typeof(UserLookupCache))] private UserLookupCache lookupCache = new TestUserLookupCache(); @@ -68,7 +70,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("load dependencies", () => { - client = new TestMultiplayerClient(multiplayerScreen.RoomManager); + client = new TestMultiplayerClient(roomManager); // The screen gets suspended so it stops receiving updates. Child = client; @@ -134,7 +136,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddServerSideRoom(new Room + roomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Playlist = @@ -164,7 +166,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddServerSideRoom(new Room + roomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Playlist = @@ -213,7 +215,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { AddStep("create room", () => { - multiplayerScreen.RoomManager.AddServerSideRoom(new Room + roomManager.AddServerSideRoom(new Room { Name = { Value = "Test Room" }, Password = { Value = "password" }, From f2340c6dac64d6c7dda95e84699586e35d81b964 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 09:48:33 +0900 Subject: [PATCH 379/961] Privatise mutable list --- .../Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs index 41102ae7b5..c3a944f93c 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs @@ -30,7 +30,8 @@ namespace osu.Game.Tests.Visual.Multiplayer [Resolved] private OsuGameBase game { get; set; } - public readonly List ServerSideRooms = new List(); + public IReadOnlyList ServerSideRooms => serverSideRooms; + private readonly List serverSideRooms = new List(); private int currentRoomId; private int currentPlaylistItemId; @@ -133,7 +134,7 @@ namespace osu.Game.Tests.Visual.Multiplayer for (int i = 0; i < room.Playlist.Count; i++) room.Playlist[i].ID = currentPlaylistItemId++; - ServerSideRooms.Add(room); + serverSideRooms.Add(room); } private Room createResponseRoom(Room room, bool withParticipants) From 060ba0692d27a42507bfcc1fedae13e89f0c8408 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 04:27:04 +0300 Subject: [PATCH 380/961] Add hash code support for `Mod` --- osu.Game/Rulesets/Mods/Mod.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index f2fd02c652..a99ddc6924 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -197,6 +197,18 @@ namespace osu.Game.Rulesets.Mods ModUtils.GetSettingUnderlyingValue(pair.Item2.GetValue(other)))); } + public override int GetHashCode() + { + var hashCode = new HashCode(); + + hashCode.Add(GetType()); + + foreach (var (_, prop) in this.GetSettingsSourceProperties()) + hashCode.Add(ModUtils.GetSettingUnderlyingValue(prop.GetValue(this))); + + return hashCode.ToHashCode(); + } + /// /// Reset all custom settings for this mod back to their defaults. /// From 0291cd5ae2eb269cf10512ce588ac5c762379ebd Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 04:27:43 +0300 Subject: [PATCH 381/961] Consider mod equality in difficulty cache lookup rather than acronym --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 6ed623d0c0..8bc043a2e9 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -297,7 +297,7 @@ namespace osu.Game.Beatmaps public bool Equals(DifficultyCacheLookup other) => Beatmap.ID == other.Beatmap.ID && Ruleset.ID == other.Ruleset.ID - && OrderedMods.Select(m => m.Acronym).SequenceEqual(other.OrderedMods.Select(m => m.Acronym)); + && OrderedMods.SequenceEqual(other.OrderedMods); public override int GetHashCode() { @@ -307,7 +307,7 @@ namespace osu.Game.Beatmaps hashCode.Add(Ruleset.ID); foreach (var mod in OrderedMods) - hashCode.Add(mod.Acronym); + hashCode.Add(mod); return hashCode.ToHashCode(); } From 32ba5255558f6057831f87123135aa64955baab8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 04:28:34 +0300 Subject: [PATCH 382/961] Track changes to mod settings in beatmap difficulty cache with 100ms debouncing --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 23 +++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 8bc043a2e9..5025e4ad4b 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -14,6 +14,7 @@ using osu.Framework.Lists; using osu.Framework.Logging; using osu.Framework.Threading; using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Database; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -56,12 +57,28 @@ namespace osu.Game.Beatmaps [Resolved] private Bindable> currentMods { get; set; } + private ModSettingChangeTracker modSettingChangeTracker; + private ScheduledDelegate debouncedModSettingsChange; + protected override void LoadComplete() { base.LoadComplete(); currentRuleset.BindValueChanged(_ => updateTrackedBindables()); - currentMods.BindValueChanged(_ => updateTrackedBindables(), true); + + currentMods.BindValueChanged(mods => + { + modSettingChangeTracker?.Dispose(); + + updateTrackedBindables(); + + modSettingChangeTracker = new ModSettingChangeTracker(mods.NewValue); + modSettingChangeTracker.SettingChanged += _ => + { + debouncedModSettingsChange?.Cancel(); + debouncedModSettingsChange = Scheduler.AddDelayed(updateTrackedBindables, 100); + }; + }, true); } /// @@ -84,7 +101,7 @@ namespace osu.Game.Beatmaps /// Retrieves a bindable containing the star difficulty of a with a given and combination. /// /// - /// The bindable will not update to follow the currently-selected ruleset and mods. + /// The bindable will not update to follow the currently-selected ruleset and mods or its settings. /// /// The to get the difficulty of. /// The to get the difficulty with. If null, the 's ruleset is used. @@ -275,6 +292,8 @@ namespace osu.Game.Beatmaps { base.Dispose(isDisposing); + modSettingChangeTracker?.Dispose(); + cancelTrackedBindableUpdate(); updateScheduler?.Dispose(); } From b419ea716b307eb54fca5892024e5066b81920f0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 04:29:15 +0300 Subject: [PATCH 383/961] Refactor beatmap info wedge to not fully refresh on star difficulty change Makes it look awkward when changing difficulty via mod settings for example. Now the changes should instead only affect the displayed components which consume it directly. --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 104 ++++++++++---------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 5b4e077100..678e7d5d73 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -21,6 +21,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Configuration; @@ -38,6 +39,8 @@ namespace osu.Game.Screens.Select public const float BORDER_THICKNESS = 2.5f; private const float shear_width = 36.75f; + private const float transition_duration = 250; + private static readonly Vector2 wedged_container_shear = new Vector2(shear_width / SongSelect.WEDGE_HEIGHT, 0); [Resolved] @@ -46,11 +49,6 @@ namespace osu.Game.Screens.Select [Resolved] private IBindable> mods { get; set; } - [Resolved] - private BeatmapDifficultyCache difficultyCache { get; set; } - - private IBindable beatmapDifficulty; - protected Container DisplayedContent { get; private set; } protected WedgeInfoText Info { get; private set; } @@ -81,20 +79,18 @@ namespace osu.Game.Screens.Select { this.MoveToX(0, 800, Easing.OutQuint); this.RotateTo(0, 800, Easing.OutQuint); - this.FadeIn(250); + this.FadeIn(transition_duration); } protected override void PopOut() { this.MoveToX(-100, 800, Easing.In); this.RotateTo(10, 800, Easing.In); - this.FadeOut(500, Easing.In); + this.FadeOut(transition_duration * 2, Easing.In); } private WorkingBeatmap beatmap; - private CancellationTokenSource cancellationSource; - public WorkingBeatmap Beatmap { get => beatmap; @@ -103,12 +99,6 @@ namespace osu.Game.Screens.Select if (beatmap == value) return; beatmap = value; - cancellationSource?.Cancel(); - cancellationSource = new CancellationTokenSource(); - - beatmapDifficulty?.UnbindAll(); - beatmapDifficulty = difficultyCache.GetBindableDifficulty(beatmap.BeatmapInfo, cancellationSource.Token); - beatmapDifficulty.BindValueChanged(_ => updateDisplay()); updateDisplay(); } @@ -128,7 +118,7 @@ namespace osu.Game.Screens.Select { State.Value = beatmap == null ? Visibility.Hidden : Visibility.Visible; - DisplayedContent?.FadeOut(250); + DisplayedContent?.FadeOut(transition_duration); DisplayedContent?.Expire(); DisplayedContent = null; } @@ -147,7 +137,7 @@ namespace osu.Game.Screens.Select Children = new Drawable[] { new BeatmapInfoWedgeBackground(beatmap), - Info = new WedgeInfoText(beatmap, ruleset.Value, mods.Value, beatmapDifficulty.Value ?? new StarDifficulty()), + Info = new WedgeInfoText(beatmap, ruleset.Value, mods.Value), } }, loaded => { @@ -160,12 +150,6 @@ namespace osu.Game.Screens.Select } } - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - cancellationSource?.Cancel(); - } - public class WedgeInfoText : Container { public OsuSpriteText VersionLabel { get; private set; } @@ -174,6 +158,9 @@ namespace osu.Game.Screens.Select public BeatmapSetOnlineStatusPill StatusPill { get; private set; } public FillFlowContainer MapperContainer { get; private set; } + private DifficultyColourBar difficultyColourBar; + private StarRatingDisplay starRatingDisplay; + private ILocalisedBindableString titleBinding; private ILocalisedBindableString artistBinding; private FillFlowContainer infoLabelContainer; @@ -182,20 +169,21 @@ namespace osu.Game.Screens.Select private readonly WorkingBeatmap beatmap; private readonly RulesetInfo ruleset; private readonly IReadOnlyList mods; - private readonly StarDifficulty starDifficulty; private ModSettingChangeTracker settingChangeTracker; - public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset, IReadOnlyList mods, StarDifficulty difficulty) + public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset, IReadOnlyList mods) { this.beatmap = beatmap; ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset; this.mods = mods; - starDifficulty = difficulty; } + private CancellationTokenSource cancellationSource; + private IBindable starDifficulty; + [BackgroundDependencyLoader] - private void load(LocalisationManager localisation) + private void load(LocalisationManager localisation, BeatmapDifficultyCache difficultyCache) { var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); @@ -207,7 +195,7 @@ namespace osu.Game.Screens.Select Children = new Drawable[] { - new DifficultyColourBar(starDifficulty) + difficultyColourBar = new DifficultyColourBar { RelativeSizeAxes = Axes.Y, Width = 20, @@ -241,14 +229,15 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Top = 14, Right = shear_width / 2 }, AutoSizeAxes = Axes.Both, Shear = wedged_container_shear, - Children = new[] + Children = new Drawable[] { - createStarRatingDisplay(starDifficulty).With(display => + starRatingDisplay = new StarRatingDisplay(default) { - display.Anchor = Anchor.TopRight; - display.Origin = Anchor.TopRight; - display.Shear = -wedged_container_shear; - }), + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Shear = -wedged_container_shear, + Alpha = 0f, + }, StatusPill = new BeatmapSetOnlineStatusPill { Anchor = Anchor.TopRight, @@ -304,6 +293,15 @@ namespace osu.Game.Screens.Select titleBinding.BindValueChanged(_ => setMetadata(metadata.Source)); artistBinding.BindValueChanged(_ => setMetadata(metadata.Source), true); + starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); + starDifficulty.BindValueChanged(s => + { + difficultyColourBar.Current.Value = s.NewValue ?? default; + + starRatingDisplay.FadeIn(transition_duration); + starRatingDisplay.Current.Value = s.NewValue ?? default; + }); + // no difficulty means it can't have a status to show if (beatmapInfo.Version == null) StatusPill.Hide(); @@ -311,13 +309,6 @@ namespace osu.Game.Screens.Select addInfoLabels(); } - private static Drawable createStarRatingDisplay(StarDifficulty difficulty) => difficulty.Stars > 0 - ? new StarRatingDisplay(difficulty) - { - Margin = new MarginPadding { Bottom = 5 } - } - : Empty(); - private void setMetadata(string source) { ArtistLabel.Text = artistBinding.Value; @@ -429,6 +420,7 @@ namespace osu.Game.Screens.Select { base.Dispose(isDisposing); settingChangeTracker?.Dispose(); + cancellationSource?.Cancel(); } public class InfoLabel : Container, IHasTooltip @@ -490,41 +482,53 @@ namespace osu.Game.Screens.Select } } - private class DifficultyColourBar : Container + public class DifficultyColourBar : Container, IHasCurrentValue { - private readonly StarDifficulty difficulty; + private readonly BindableWithCurrent current = new BindableWithCurrent(); - public DifficultyColourBar(StarDifficulty difficulty) + public Bindable Current { - this.difficulty = difficulty; + get => current.Current; + set => current.Current = value; } + [Resolved] + private OsuColour colours { get; set; } + [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { const float full_opacity_ratio = 0.7f; - var difficultyColour = colours.ForStarDifficulty(difficulty.Stars); - Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = difficultyColour, Width = full_opacity_ratio, }, new Box { RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, - Colour = difficultyColour, Alpha = 0.5f, X = full_opacity_ratio, Width = 1 - full_opacity_ratio, } }; } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(c => + { + this.FadeColour(colours.ForStarDifficulty(c.NewValue.Stars), transition_duration, Easing.OutQuint); + }, true); + + FinishTransforms(true); + } } } } From a329216ff350d2f84e66d48e8a4fdbf03e4d9dd0 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 04:28:07 +0300 Subject: [PATCH 384/961] Convert beatmap difficulty test into test scene and extend coverage --- .../Beatmaps/BeatmapDifficultyCacheTest.cs | 56 ------- .../TestSceneBeatmapDifficultyCache.cs | 158 ++++++++++++++++++ 2 files changed, 158 insertions(+), 56 deletions(-) delete mode 100644 osu.Game.Tests/Beatmaps/BeatmapDifficultyCacheTest.cs create mode 100644 osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs diff --git a/osu.Game.Tests/Beatmaps/BeatmapDifficultyCacheTest.cs b/osu.Game.Tests/Beatmaps/BeatmapDifficultyCacheTest.cs deleted file mode 100644 index d407c0663f..0000000000 --- a/osu.Game.Tests/Beatmaps/BeatmapDifficultyCacheTest.cs +++ /dev/null @@ -1,56 +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.Game.Beatmaps; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.Osu.Mods; - -namespace osu.Game.Tests.Beatmaps -{ - [TestFixture] - public class BeatmapDifficultyCacheTest - { - [Test] - public void TestKeyEqualsWithDifferentModInstances() - { - var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); - var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); - - Assert.That(key1, Is.EqualTo(key2)); - } - - [Test] - public void TestKeyEqualsWithDifferentModOrder() - { - var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); - var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() }); - - Assert.That(key1, Is.EqualTo(key2)); - } - - [TestCase(1.3, DifficultyRating.Easy)] - [TestCase(1.993, DifficultyRating.Easy)] - [TestCase(1.998, DifficultyRating.Normal)] - [TestCase(2.4, DifficultyRating.Normal)] - [TestCase(2.693, DifficultyRating.Normal)] - [TestCase(2.698, DifficultyRating.Hard)] - [TestCase(3.5, DifficultyRating.Hard)] - [TestCase(3.993, DifficultyRating.Hard)] - [TestCase(3.997, DifficultyRating.Insane)] - [TestCase(5.0, DifficultyRating.Insane)] - [TestCase(5.292, DifficultyRating.Insane)] - [TestCase(5.297, DifficultyRating.Expert)] - [TestCase(6.2, DifficultyRating.Expert)] - [TestCase(6.493, DifficultyRating.Expert)] - [TestCase(6.498, DifficultyRating.ExpertPlus)] - [TestCase(8.3, DifficultyRating.ExpertPlus)] - public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket) - { - var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating); - - Assert.AreEqual(expectedBracket, actualBracket); - } - } -} diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs new file mode 100644 index 0000000000..b6ba5b748a --- /dev/null +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -0,0 +1,158 @@ +// 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 System.Threading; +using System.Threading.Tasks; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Tests.Visual; + +namespace osu.Game.Tests.Beatmaps +{ + [HeadlessTest] + public class TestSceneBeatmapDifficultyCache : OsuTestScene + { + public const double BASE_STARS = 5.55; + + private BeatmapSetInfo importedSet; + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + private TestBeatmapDifficultyCache difficultyCache; + + private IBindable starDifficultyBindable; + private Queue> starDifficultyChangesQueue; + + [BackgroundDependencyLoader] + private void load(OsuGameBase osu) + { + importedSet = ImportBeatmapTest.LoadQuickOszIntoOsu(osu).Result; + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("setup difficulty cache", () => + { + SelectedMods.Value = Array.Empty(); + + Child = difficultyCache = new TestBeatmapDifficultyCache(); + + starDifficultyChangesQueue = new Queue>(); + starDifficultyBindable = difficultyCache.GetBindableDifficulty(importedSet.Beatmaps.First()); + starDifficultyBindable.BindValueChanged(starDifficultyChangesQueue.Enqueue); + }); + + AddAssert($"star difficulty -> {BASE_STARS}", () => + starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS && + starDifficultyChangesQueue.Count == 0); + } + + [Test] + public void TestStarDifficultyChangesOnModSettings() + { + OsuModDoubleTime dt = null; + + AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); + AddAssert($"star difficulty -> {BASE_STARS + 1.5}", () => + starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.5 && + starDifficultyChangesQueue.Count == 0); + + AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25); + AddAssert($"star difficulty -> {BASE_STARS + 1.25}", () => + starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.25 && + starDifficultyChangesQueue.Count == 0); + + AddStep("change selected mod to NC", () => SelectedMods.Value = new[] { new OsuModNightcore { SpeedChange = { Value = 1.75 } } }); + AddAssert($"star difficulty -> {BASE_STARS + 1.75}", () => + starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.75 && + starDifficultyChangesQueue.Count == 0); + } + + [Test] + public void TestKeyEqualsWithDifferentModInstances() + { + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); + + Assert.That(key1, Is.EqualTo(key2)); + Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode())); + } + + [Test] + public void TestKeyEqualsWithDifferentModOrder() + { + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHardRock(), new OsuModHidden() }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModHidden(), new OsuModHardRock() }); + + Assert.That(key1, Is.EqualTo(key2)); + Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode())); + } + + [Test] + public void TestKeyDoesntEqualWithDifferentModSettings() + { + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.1 } } }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.9 } } }); + + Assert.That(key1, Is.Not.EqualTo(key2)); + Assert.That(key1.GetHashCode(), Is.Not.EqualTo(key2.GetHashCode())); + } + + [Test] + public void TestKeyEqualWithMatchingModSettings() + { + var key1 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); + var key2 = new BeatmapDifficultyCache.DifficultyCacheLookup(new BeatmapInfo { ID = 1234 }, new RulesetInfo { ID = 0 }, new Mod[] { new OsuModDoubleTime { SpeedChange = { Value = 1.25 } } }); + + Assert.That(key1, Is.EqualTo(key2)); + Assert.That(key1.GetHashCode(), Is.EqualTo(key2.GetHashCode())); + } + + [TestCase(1.3, DifficultyRating.Easy)] + [TestCase(1.993, DifficultyRating.Easy)] + [TestCase(1.998, DifficultyRating.Normal)] + [TestCase(2.4, DifficultyRating.Normal)] + [TestCase(2.693, DifficultyRating.Normal)] + [TestCase(2.698, DifficultyRating.Hard)] + [TestCase(3.5, DifficultyRating.Hard)] + [TestCase(3.993, DifficultyRating.Hard)] + [TestCase(3.997, DifficultyRating.Insane)] + [TestCase(5.0, DifficultyRating.Insane)] + [TestCase(5.292, DifficultyRating.Insane)] + [TestCase(5.297, DifficultyRating.Expert)] + [TestCase(6.2, DifficultyRating.Expert)] + [TestCase(6.493, DifficultyRating.Expert)] + [TestCase(6.498, DifficultyRating.ExpertPlus)] + [TestCase(8.3, DifficultyRating.ExpertPlus)] + public void TestDifficultyRatingMapping(double starRating, DifficultyRating expectedBracket) + { + var actualBracket = BeatmapDifficultyCache.GetDifficultyRating(starRating); + + Assert.AreEqual(expectedBracket, actualBracket); + } + + private class TestBeatmapDifficultyCache : BeatmapDifficultyCache + { + protected override Task ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default) + { + var rateAdjust = lookup.OrderedMods.OfType().SingleOrDefault(); + if (rateAdjust != null) + return Task.FromResult(new StarDifficulty(BASE_STARS + rateAdjust.SpeedChange.Value, 0)); + + return Task.FromResult(new StarDifficulty(BASE_STARS, 0)); + } + } + } +} From eb6c6830bcd977430a710efaf21e65f38fa2c5f9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 05:45:03 +0300 Subject: [PATCH 385/961] Add visual test slider for changing star difficulty in beatmap wedge --- .../Visual/SongSelect/TestSceneBeatmapInfoWedge.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index a416fd4daf..2b38c4f936 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; @@ -65,6 +66,12 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("show", () => { infoWedge.Show(); }); + AddSliderStep("change star difficulty", 0, 11.9, 5.55, v => + { + foreach (var hasCurrentValue in infoWedge.Info.ChildrenOfType>()) + hasCurrentValue.Current.Value = new StarDifficulty(v, 0); + }); + foreach (var rulesetInfo in rulesets.AvailableRulesets) { var instance = rulesetInfo.CreateInstance(); From adb4fd5a2bcdf08ebc6bfe47bc45ba7c41e2c8c1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 12:31:33 +0900 Subject: [PATCH 386/961] Load only sections content asynchronously, showing the header initially --- osu.Game/Overlays/SettingsPanel.cs | 150 ++++++++++++++++------------- 1 file changed, 82 insertions(+), 68 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 6593b6cb1e..fea797287e 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; @@ -61,6 +62,10 @@ namespace osu.Game.Overlays private LoadingLayer loading; + private readonly List loadableSections = new List(); + + private Task sectionsLoadingTask; + protected SettingsPanel(bool showSidebar) { this.showSidebar = showSidebar; @@ -96,7 +101,7 @@ namespace osu.Game.Overlays } }; - SectionsContainer = new SettingsSectionsContainer + Add(SectionsContainer = new SettingsSectionsContainer { Masking = true, RelativeSizeAxes = Axes.Both, @@ -113,8 +118,8 @@ namespace osu.Game.Overlays Bottom = 20 }, }, - Footer = CreateFooter() - }; + Footer = CreateFooter().With(f => f.Alpha = 0) + }); if (showSidebar) { @@ -124,76 +129,13 @@ namespace osu.Game.Overlays CreateSections()?.ForEach(AddSection); } - private void ensureContentLoaded() - { - if (SectionsContainer.LoadState > LoadState.NotLoaded) - return; - - LoadComponentAsync(SectionsContainer, d => - { - ContentContainer.Add(d); - d.FadeInFromZero(750, Easing.OutQuint); - loading.Hide(); - - searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true); - searchTextBox.TakeFocus(); - - if (Sidebar == null) - return; - - LoadComponentsAsync(createSidebarButtons(), buttons => - { - float delay = 0; - - foreach (var button in buttons) - { - Sidebar.Add(button); - - button.FadeOut() - .Delay(delay) - .FadeInFromZero(1000, Easing.OutQuint); - - delay += 30; - } - - SectionsContainer.SelectedSection.BindValueChanged(section => - { - if (selectedSidebarButton != null) - selectedSidebarButton.Selected = false; - - selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); - selectedSidebarButton.Selected = true; - }, true); - }); - }); - } - - private IEnumerable createSidebarButtons() - { - foreach (var section in SectionsContainer) - { - yield return new SidebarButton - { - Section = section, - Action = () => - { - if (!SectionsContainer.IsLoaded) - return; - - SectionsContainer.ScrollTo(section); - Sidebar.State = ExpandedState.Contracted; - }, - }; - } - } - protected void AddSection(SettingsSection section) { if (IsLoaded) // just to keep things simple. can be accommodated for if we ever need it. throw new InvalidOperationException("All sections must be added before the panel is loaded."); - SectionsContainer.Add(section); + loadableSections.Add(section); } protected virtual Drawable CreateHeader() => new Container(); @@ -210,7 +152,7 @@ namespace osu.Game.Overlays // this is done as there is still a brief stutter during load completion which is more visible if the transition is in progress. // the eventual goal would be to remove the need for this by splitting up load into smaller work pieces, or fixing the remaining // load complete overheads. - Scheduler.AddDelayed(ensureContentLoaded, TRANSITION_LENGTH / 3); + Scheduler.AddDelayed(loadSections, TRANSITION_LENGTH / 3); Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint); @@ -250,6 +192,78 @@ namespace osu.Game.Overlays Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } + private const double fade_in_duration = 1000; + + private void loadSections() + { + if (sectionsLoadingTask != null) + return; + + sectionsLoadingTask = LoadComponentsAsync(loadableSections, sections => + { + SectionsContainer.AddRange(sections); + SectionsContainer.Footer.FadeInFromZero(fade_in_duration, Easing.OutQuint); + SectionsContainer.SearchContainer.FadeInFromZero(fade_in_duration, Easing.OutQuint); + + loading.Hide(); + + searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true); + searchTextBox.TakeFocus(); + + loadSidebarButtons(); + }); + } + + private void loadSidebarButtons() + { + if (Sidebar == null) + return; + + LoadComponentsAsync(createSidebarButtons(), buttons => + { + float delay = 0; + + foreach (var button in buttons) + { + Sidebar.Add(button); + + button.FadeOut() + .Delay(delay) + .FadeInFromZero(fade_in_duration, Easing.OutQuint); + + delay += 40; + } + + SectionsContainer.SelectedSection.BindValueChanged(section => + { + if (selectedSidebarButton != null) + selectedSidebarButton.Selected = false; + + selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); + selectedSidebarButton.Selected = true; + }, true); + }); + } + + private IEnumerable createSidebarButtons() + { + foreach (var section in SectionsContainer) + { + yield return new SidebarButton + { + Section = section, + Action = () => + { + if (!SectionsContainer.IsLoaded) + return; + + SectionsContainer.ScrollTo(section); + Sidebar.State = ExpandedState.Contracted; + }, + }; + } + } + private class NonMaskedContent : Container { // masking breaks the pan-out transform with nested sub-settings panels. From 212842c5373bda3b369e1ea9d9d7535637634684 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 12:38:44 +0900 Subject: [PATCH 387/961] Fix initial `LayoutSettings` animation in a more reliable way --- .../Sections/Graphics/LayoutSettings.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs index 277e344d84..d29f5fef39 100644 --- a/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Graphics/LayoutSettings.cs @@ -175,16 +175,14 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics scalingMode.BindValueChanged(mode => { scalingSettings.ClearTransforms(); - scalingSettings.AutoSizeDuration = transition_duration; scalingSettings.AutoSizeEasing = Easing.OutQuint; - scalingSettings.AutoSizeAxes = mode.NewValue != ScalingMode.Off ? Axes.Y : Axes.None; - if (mode.NewValue == ScalingMode.Off) - scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint); + updateScalingModeVisibility(); + }); - scalingSettings.ForEach(s => s.TransferValueOnCommit = mode.NewValue == ScalingMode.Everything); - }, true); + // initial update bypasses transforms + updateScalingModeVisibility(); void updateResolutionDropdown() { @@ -193,6 +191,15 @@ namespace osu.Game.Overlays.Settings.Sections.Graphics else resolutionDropdown.Hide(); } + + void updateScalingModeVisibility() + { + if (scalingMode.Value == ScalingMode.Off) + scalingSettings.ResizeHeightTo(0, transition_duration, Easing.OutQuint); + + scalingSettings.AutoSizeAxes = scalingMode.Value != ScalingMode.Off ? Axes.Y : Axes.None; + scalingSettings.ForEach(s => s.TransferValueOnCommit = scalingMode.Value == ScalingMode.Everything); + } } private void bindPreviewEvent(Bindable bindable) From bc86bafc0898b2d6d288ef81b2f3a10f4eb1331d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 12:48:30 +0900 Subject: [PATCH 388/961] Fix `RestoreDefaultValueButton`'s colour weirdness --- osu.Game/Graphics/UserInterface/OsuButton.cs | 1 + osu.Game/Overlays/RestoreDefaultValueButton.cs | 11 ++++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index cd9ca9f87f..82a3e73b84 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -36,6 +36,7 @@ namespace osu.Game.Graphics.UserInterface public Color4 BackgroundColour { + get => backgroundColour ?? Color4.White; set { backgroundColour = value; diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 62f5222012..87a294cc10 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -45,8 +45,6 @@ namespace osu.Game.Overlays } } - private Color4 buttonColour; - private bool hovering; public RestoreDefaultValueButton() @@ -61,12 +59,11 @@ namespace osu.Game.Overlays private void load(OsuColour colour) { BackgroundColour = colour.Yellow; - buttonColour = colour.Yellow; Content.Width = 0.33f; Content.CornerRadius = 3; Content.EdgeEffect = new EdgeEffectParameters { - Colour = buttonColour.Opacity(0.1f), + Colour = BackgroundColour.Opacity(0.1f), Type = EdgeEffectType.Glow, Radius = 2, }; @@ -87,7 +84,7 @@ namespace osu.Game.Overlays // avoid unnecessary transforms on first display. Alpha = currentAlpha; - Colour = currentColour; + Background.Colour = currentColour; } public LocalisableString TooltipText => "revert to default"; @@ -108,7 +105,7 @@ namespace osu.Game.Overlays public void UpdateState() => Scheduler.AddOnce(updateState); private float currentAlpha => current.IsDefault ? 0f : hovering && !current.Disabled ? 1f : 0.65f; - private ColourInfo currentColour => current.Disabled ? Color4.Gray : buttonColour; + private ColourInfo currentColour => current.Disabled ? Color4.Gray : BackgroundColour; private void updateState() { @@ -116,7 +113,7 @@ namespace osu.Game.Overlays return; this.FadeTo(currentAlpha, 200, Easing.OutQuint); - this.FadeColour(currentColour, 200, Easing.OutQuint); + Background.FadeColour(currentColour, 200, Easing.OutQuint); } } } From 1e2c0031d7473302f2f39bee34f4e4d2d4088048 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 13:34:44 +0900 Subject: [PATCH 389/961] Remove unused usings --- osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs index dbac132faf..73bab31e82 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainDecaySkill.cs @@ -2,8 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; -using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; From 081524b6c862af923b6f1084e3182f0abd85f59f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 13:44:21 +0900 Subject: [PATCH 390/961] Privatise setters --- osu.Game/Screens/Play/PlayerLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index a6592e4d24..969527a758 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -46,14 +46,14 @@ namespace osu.Game.Screens.Play protected override bool PlayResumeSound => false; - protected BeatmapMetadataDisplay MetadataInfo; + protected BeatmapMetadataDisplay MetadataInfo { get; private set; } /// /// A fill flow containing the player settings groups, exposed for the ability to hide it from inheritors of the player loader. /// - protected FillFlowContainer PlayerSettings; + protected FillFlowContainer PlayerSettings { get; private set; } - protected VisualSettings VisualSettings; + protected VisualSettings VisualSettings { get; private set; } protected Task LoadTask { get; private set; } From 3a7b9bf096d1b3c259c8db8c7c44f9c99dc44ff5 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 17 Aug 2021 08:56:49 +0300 Subject: [PATCH 391/961] Fix `MatchSettingsOverlay` not resetting focus on hide properly --- .../Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 2676453a7e..62a968b508 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -41,11 +41,13 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override void PopIn() { + base.PopIn(); Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint); } protected override void PopOut() { + base.PopOut(); Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine); } From 82eddeffefe1a33035cd44a7a7435c650c316d00 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 16:13:45 +0900 Subject: [PATCH 392/961] Add `LocalUserPlayInfo` interface to convey common information about player status --- osu.Desktop/Windows/GameplayWinKeyBlocker.cs | 8 ++++---- osu.Game/Input/ConfineMouseTracker.cs | 5 +++-- osu.Game/OsuGame.cs | 4 +++- osu.Game/Performance/HighPerformanceSession.cs | 5 +++-- osu.Game/Screens/Play/ILocalUserPlayInfo.cs | 17 +++++++++++++++++ osu.Game/Screens/Play/Player.cs | 4 +++- 6 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Screens/Play/ILocalUserPlayInfo.cs diff --git a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs index efc3f21149..dbfd170ea1 100644 --- a/osu.Desktop/Windows/GameplayWinKeyBlocker.cs +++ b/osu.Desktop/Windows/GameplayWinKeyBlocker.cs @@ -5,23 +5,23 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Platform; -using osu.Game; using osu.Game.Configuration; +using osu.Game.Screens.Play; namespace osu.Desktop.Windows { public class GameplayWinKeyBlocker : Component { private Bindable disableWinKey; - private Bindable localUserPlaying; + private IBindable localUserPlaying; [Resolved] private GameHost host { get; set; } [BackgroundDependencyLoader] - private void load(OsuGame game, OsuConfigManager config) + private void load(ILocalUserPlayInfo localUserInfo, OsuConfigManager config) { - localUserPlaying = game.LocalUserPlaying.GetBoundCopy(); + localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy(); localUserPlaying.BindValueChanged(_ => updateBlocking()); disableWinKey = config.GetBindable(OsuSetting.GameplayDisableWinKey); diff --git a/osu.Game/Input/ConfineMouseTracker.cs b/osu.Game/Input/ConfineMouseTracker.cs index 75d9c8debb..d2bf953dbc 100644 --- a/osu.Game/Input/ConfineMouseTracker.cs +++ b/osu.Game/Input/ConfineMouseTracker.cs @@ -7,6 +7,7 @@ using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Input; using osu.Game.Configuration; +using osu.Game.Screens.Play; namespace osu.Game.Input { @@ -24,14 +25,14 @@ namespace osu.Game.Input private IBindable localUserPlaying; [BackgroundDependencyLoader] - private void load(OsuGame game, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager) + private void load(ILocalUserPlayInfo localUserInfo, FrameworkConfigManager frameworkConfigManager, OsuConfigManager osuConfigManager) { frameworkConfineMode = frameworkConfigManager.GetBindable(FrameworkSetting.ConfineMouseMode); frameworkWindowMode = frameworkConfigManager.GetBindable(FrameworkSetting.WindowMode); frameworkWindowMode.BindValueChanged(_ => updateConfineMode()); osuConfineMode = osuConfigManager.GetBindable(OsuSetting.ConfineMouseMode); - localUserPlaying = game.LocalUserPlaying.GetBoundCopy(); + localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy(); osuConfineMode.ValueChanged += _ => updateConfineMode(); localUserPlaying.BindValueChanged(_ => updateConfineMode(), true); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index fb682e0909..0db63df69b 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -62,7 +62,7 @@ namespace osu.Game /// The full osu! experience. Builds on top of to add menus and binding logic /// for initial components that are generally retrieved via DI. /// - public class OsuGame : OsuGameBase, IKeyBindingHandler + public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUserPlayInfo { /// /// The amount of global offset to apply when a left/right anchored overlay is displayed (ie. settings or notifications). @@ -1085,5 +1085,7 @@ namespace osu.Game if (newScreen == null) Exit(); } + + IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } } diff --git a/osu.Game/Performance/HighPerformanceSession.cs b/osu.Game/Performance/HighPerformanceSession.cs index 661c1046f1..3ef0e0bf93 100644 --- a/osu.Game/Performance/HighPerformanceSession.cs +++ b/osu.Game/Performance/HighPerformanceSession.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Screens.Play; namespace osu.Game.Performance { @@ -12,9 +13,9 @@ namespace osu.Game.Performance private readonly IBindable localUserPlaying = new Bindable(); [BackgroundDependencyLoader] - private void load(OsuGame game) + private void load(ILocalUserPlayInfo localUserInfo) { - localUserPlaying.BindTo(game.LocalUserPlaying); + localUserPlaying.BindTo(localUserInfo.IsPlaying); } protected override void LoadComplete() diff --git a/osu.Game/Screens/Play/ILocalUserPlayInfo.cs b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs new file mode 100644 index 0000000000..64c3f97305 --- /dev/null +++ b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs @@ -0,0 +1,17 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; + +namespace osu.Game.Screens.Play +{ + [Cached] + public interface ILocalUserPlayInfo + { + /// + /// Whether the local user is currently playing. + /// + public IBindable IsPlaying { get; } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 09eaf1c543..5461c6ac6c 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.Play { [Cached] [Cached(typeof(ISamplePlaybackDisabler))] - public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler + public abstract class Player : ScreenWithBeatmapBackground, ISamplePlaybackDisabler, ILocalUserPlayInfo { /// /// The delay upon completion of the beatmap before displaying the results screen. @@ -1052,5 +1052,7 @@ namespace osu.Game.Screens.Play #endregion IBindable ISamplePlaybackDisabler.SamplePlaybackDisabled => samplePlaybackDisabled; + + IBindable ILocalUserPlayInfo.IsPlaying => LocalUserPlaying; } } From e3b29df29930e4e5f79072b4b762fad0f27fd31c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 14:39:08 +0900 Subject: [PATCH 393/961] Add test scene for `MultiplayerPlayer` --- .../Multiplayer/TestSceneMultiplayerPlayer.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs new file mode 100644 index 0000000000..80da7a7e5e --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs @@ -0,0 +1,38 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay.Multiplayer; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMultiplayerPlayer : MultiplayerTestScene + { + private MultiplayerPlayer player; + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("set beatmap", () => + { + Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); + }); + + AddStep("initialise gameplay", () => + { + Stack.Push(player = new MultiplayerPlayer(Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray())); + }); + } + + [Test] + public void TestGameplay() + { + AddUntilStep("wait for gameplay start", () => player.LocalUserPlaying.Value); + } + } +} From 0d283aa6a348bef4702a7d1d3bf8010195c70098 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 14:39:22 +0900 Subject: [PATCH 394/961] Expose `LocalUserPlaying` from `Player` --- .../Visual/Gameplay/TestSceneOverlayActivation.cs | 2 -- osu.Game/Screens/Play/Player.cs | 6 ++++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs index 4fa4c00981..b308f3d7d8 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneOverlayActivation.cs @@ -3,7 +3,6 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; using osu.Game.Overlays; using osu.Game.Rulesets; @@ -66,7 +65,6 @@ namespace osu.Game.Tests.Visual.Gameplay protected class OverlayTestPlayer : TestPlayer { public new OverlayActivation OverlayActivationMode => base.OverlayActivationMode.Value; - public new Bindable LocalUserPlaying => base.LocalUserPlaying; } } } diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 5461c6ac6c..59c7abb299 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -75,7 +75,9 @@ namespace osu.Game.Screens.Play private readonly Bindable storyboardReplacesBackground = new Bindable(); - protected readonly Bindable LocalUserPlaying = new Bindable(); + public IBindable LocalUserPlaying => localUserPlaying; + + private readonly Bindable localUserPlaying = new Bindable(); public int RestartCount; @@ -442,7 +444,7 @@ namespace osu.Game.Screens.Play { bool inGameplay = !DrawableRuleset.HasReplayLoaded.Value && !DrawableRuleset.IsPaused.Value && !breakTracker.IsBreakTime.Value; OverlayActivationMode.Value = inGameplay ? OverlayActivation.Disabled : OverlayActivation.UserTriggered; - LocalUserPlaying.Value = inGameplay; + localUserPlaying.Value = inGameplay; } private void updateSampleDisabledState() From 35b9f84c00efa0aacc6c01b0ecc00c129ac27a1d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 14:39:51 +0900 Subject: [PATCH 395/961] Expose `StandAloneChatDisplay.Textbox` --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 8b0caddbc6..160c620214 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -22,7 +22,7 @@ namespace osu.Game.Online.Chat { public readonly Bindable Channel = new Bindable(); - private readonly FocusedTextBox textbox; + protected readonly FocusedTextBox Textbox; protected ChannelManager ChannelManager; @@ -54,7 +54,7 @@ namespace osu.Game.Online.Chat if (postingTextbox) { - AddInternal(textbox = new FocusedTextBox + AddInternal(Textbox = new FocusedTextBox { RelativeSizeAxes = Axes.X, Height = textbox_height, @@ -65,7 +65,7 @@ namespace osu.Game.Online.Chat Origin = Anchor.BottomLeft, }); - textbox.OnCommit += postMessage; + Textbox.OnCommit += postMessage; } Channel.BindValueChanged(channelChanged); @@ -82,7 +82,7 @@ namespace osu.Game.Online.Chat private void postMessage(TextBox sender, bool newtext) { - var text = textbox.Text.Trim(); + var text = Textbox.Text.Trim(); if (string.IsNullOrWhiteSpace(text)) return; @@ -92,7 +92,7 @@ namespace osu.Game.Online.Chat else ChannelManager?.PostMessage(text, target: Channel.Value); - textbox.Text = string.Empty; + Textbox.Text = string.Empty; } protected virtual ChatLine CreateMessage(Message message) => new StandAloneMessage(message); From b82f92d7b8913d039cae235a94488047e293aec4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 14:57:38 +0900 Subject: [PATCH 396/961] Adjust background colours of textbox in chat display --- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 160c620214..9d23a089df 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -30,6 +30,8 @@ namespace osu.Game.Online.Chat private readonly bool postingTextbox; + protected readonly Box Background; + private const float textbox_height = 30; /// @@ -44,7 +46,7 @@ namespace osu.Game.Online.Chat InternalChildren = new Drawable[] { - new Box + Background = new Box { Colour = Color4.Black, Alpha = 0.8f, @@ -54,7 +56,7 @@ namespace osu.Game.Online.Chat if (postingTextbox) { - AddInternal(Textbox = new FocusedTextBox + AddInternal(Textbox = new ChatTextBox { RelativeSizeAxes = Axes.X, Height = textbox_height, @@ -110,6 +112,17 @@ namespace osu.Game.Online.Chat AddInternal(drawableChannel); } + public class ChatTextBox : FocusedTextBox + { + protected override void LoadComplete() + { + base.LoadComplete(); + + BackgroundUnfocused = new Color4(10, 10, 10, 10); + BackgroundFocused = new Color4(10, 10, 10, 255); + } + } + public class StandAloneDrawableChannel : DrawableChannel { public Func CreateChatLineAction; From 30eee363dcac3226fa679853f4ed40d060643334 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 14:57:48 +0900 Subject: [PATCH 397/961] Add chat display during multiplayer gameplay --- .../Multiplayer/GameplayChatDisplay.cs | 62 +++++++++++++++++++ .../Multiplayer/MultiplayerPlayer.cs | 10 ++- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs new file mode 100644 index 0000000000..5b33fa1844 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -0,0 +1,62 @@ +// 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.Screens.OnlinePlay.Match.Components; +using osu.Game.Screens.Play; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer +{ + public class GameplayChatDisplay : MatchChatDisplay + { + [Resolved] + private ILocalUserPlayInfo localUserInfo { get; set; } + + private IBindable localUserPlaying = new Bindable(); + + public Bindable Expanded = new Bindable(); + + private const float height = 100; + + public GameplayChatDisplay() + { + RelativeSizeAxes = Axes.X; + + Background.Alpha = 0.2f; + } + + private void expandedChanged(ValueChangedEvent expanded) + { + if (expanded.NewValue) + { + this.FadeIn(300, Easing.OutQuint); + this.ResizeHeightTo(height, 500, Easing.OutQuint); + } + else + { + this.FadeOut(300, Easing.OutQuint); + this.ResizeHeightTo(0, 500, Easing.OutQuint); + } + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + localUserPlaying = localUserInfo.IsPlaying.GetBoundCopy(); + localUserPlaying.BindValueChanged(playing => + { + // for now let's never hold focus. this avoid misdirected gameplay keys entering chat. + // note that this is done within this callback as it triggers an un-focus as well. + Textbox.HoldFocus = false; + + // only hold focus (after sending a message) during breaks + Textbox.ReleaseFocusOnCommit = playing.NewValue; + }, true); + + Expanded.BindValueChanged(expandedChanged, true); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index ca1a3710ab..24657943d7 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -68,6 +68,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, + Spacing = new Vector2(5) }); // todo: this should be implemented via a custom HUD implementation, and correctly masked to the main content area. @@ -78,7 +79,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer ((IBindable)leaderboard.Expanded).BindTo(HUDOverlay.ShowHud); - leaderboardFlow.Add(l); + leaderboardFlow.Insert(0, l); if (leaderboard.TeamScores.Count >= 2) { @@ -87,10 +88,15 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Team1Score = { BindTarget = leaderboard.TeamScores.First().Value }, Team2Score = { BindTarget = leaderboard.TeamScores.Last().Value }, Expanded = { BindTarget = HUDOverlay.ShowHud }, - }, leaderboardFlow.Add); + }, scoreDisplay => leaderboardFlow.Insert(1, scoreDisplay)); } }); + LoadComponentAsync(new GameplayChatDisplay + { + Expanded = { BindTarget = HUDOverlay.ShowHud }, + }, chat => leaderboardFlow.Insert(2, chat)); + HUDOverlay.Add(loadingDisplay = new LoadingLayer(true) { Depth = float.MaxValue }); } From 124f149cb5f861de220d98c5da7f0a2a19b7a9d1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 15:05:36 +0900 Subject: [PATCH 398/961] Add key binding to focus chat input --- .../Input/Bindings/GlobalActionContainer.cs | 4 ++++ .../Multiplayer/GameplayChatDisplay.cs | 20 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index d3cc90ef99..66edb25d64 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -90,6 +90,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward), new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), + new KeyBinding(InputKey.Tab, GlobalAction.FocusChatInput), }; public IEnumerable SongSelectKeyBindings => new[] @@ -280,5 +281,8 @@ namespace osu.Game.Input.Bindings [Description("Seek replay backward")] SeekReplayBackward, + + [Description("Focus chat")] + FocusChatInput } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 5b33fa1844..40da8d0a84 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -4,12 +4,14 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; namespace osu.Game.Screens.OnlinePlay.Multiplayer { - public class GameplayChatDisplay : MatchChatDisplay + public class GameplayChatDisplay : MatchChatDisplay, IKeyBindingHandler { [Resolved] private ILocalUserPlayInfo localUserInfo { get; set; } @@ -58,5 +60,21 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Expanded.BindValueChanged(expandedChanged, true); } + + public bool OnPressed(GlobalAction action) + { + switch (action) + { + case GlobalAction.FocusChatInput: + Textbox.TakeFocus(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } } } From 6a2d82c81aa6cd9ff1f6dae57b561ff1132c5367 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 15:11:45 +0900 Subject: [PATCH 399/961] Add test coverage --- .../TestSceneGameplayChatDisplay.cs | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs new file mode 100644 index 0000000000..795963a1ba --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -0,0 +1,85 @@ +// 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 Moq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.Play; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneGameplayChatDisplay : MultiplayerTestScene + { + private GameplayChatDisplay chatDisplay; + + [Cached(typeof(ILocalUserPlayInfo))] + private ILocalUserPlayInfo localUserInfo; + + private readonly Bindable localUserPlaying = new Bindable(); + + private TextBox textBox => chatDisplay.ChildrenOfType().First(); + + public TestSceneGameplayChatDisplay() + { + var mockLocalUserInfo = new Mock(); + mockLocalUserInfo.SetupGet(i => i.IsPlaying).Returns(localUserPlaying); + + localUserInfo = mockLocalUserInfo.Object; + } + + [SetUpSteps] + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.5f, + }); + + AddStep("expand", () => chatDisplay.Expanded.Value = true); + } + + [Test] + public void TestFocusDroppedWhenPlaying() + { + assertChatFocused(false); + + AddStep("focus chat", () => + { + InputManager.MoveMouseTo(textBox); + InputManager.Click(MouseButton.Left); + }); + + setLocalUserPlaying(true); + assertChatFocused(false); + + // should still stay non-focused even after entering a new break section. + setLocalUserPlaying(false); + assertChatFocused(false); + } + + [Test] + public void TestFocusOnTabKey() + { + assertChatFocused(false); + AddStep("press tab", () => InputManager.Key(Key.Tab)); + assertChatFocused(true); + } + + private void assertChatFocused(bool isFocused) => + AddAssert($"chat {(isFocused ? "focused" : "not focused")}", () => textBox.HasFocus == isFocused); + + private void setLocalUserPlaying(bool playing) => + AddStep($"local user {(playing ? "playing" : "not playing")}", () => localUserPlaying.Value = playing); + } +} From 6ee6a468941525b3b6d98369c4f3fdcdd30c58d4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 16:22:12 +0900 Subject: [PATCH 400/961] Remove unnecessary `public` prefix in interface specification --- osu.Game/Screens/Play/ILocalUserPlayInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/ILocalUserPlayInfo.cs b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs index 64c3f97305..9a2259b12f 100644 --- a/osu.Game/Screens/Play/ILocalUserPlayInfo.cs +++ b/osu.Game/Screens/Play/ILocalUserPlayInfo.cs @@ -12,6 +12,6 @@ namespace osu.Game.Screens.Play /// /// Whether the local user is currently playing. /// - public IBindable IsPlaying { get; } + IBindable IsPlaying { get; } } } From 72dd18732d44efb3c24e732fa59be8cae0f52e9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 16:37:18 +0900 Subject: [PATCH 401/961] Fix regressed tests --- osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs index 8632bfe681..57ba051214 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneKeyBindingPanel.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Settings [SetUpSteps] public void SetUpSteps() { - AddUntilStep("wait for load", () => panel.ChildrenOfType().Any()); + AddUntilStep("wait for load", () => panel.ChildrenOfType().Any()); AddStep("Scroll to top", () => panel.ChildrenOfType().First().ScrollToTop()); AddWaitStep("wait for scroll", 5); } From 8a1651e8308f1ee865d22cc81f9bc87192e962a7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 17:04:32 +0900 Subject: [PATCH 402/961] Reorganise methods in `PollingComponent` --- osu.Game/Online/PollingComponent.cs | 73 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/osu.Game/Online/PollingComponent.cs b/osu.Game/Online/PollingComponent.cs index 806c0047e7..243be8da44 100644 --- a/osu.Game/Online/PollingComponent.cs +++ b/osu.Game/Online/PollingComponent.cs @@ -47,39 +47,13 @@ namespace osu.Game.Online pollIfNecessary(); } - private bool pollIfNecessary() + /// + /// Immediately performs a . + /// + public void PollImmediately() { - // we must be loaded so we have access to clock. - if (!IsLoaded) return false; - - // there's already a poll process running. - if (pollingActive) return false; - - // don't try polling if the time between polls hasn't been set. - if (TimeBetweenPolls.Value == 0) return false; - - if (!lastTimePolled.HasValue) - { - doPoll(); - return true; - } - - if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value) - { - doPoll(); - return true; - } - - // not enough time has passed since the last poll. we do want to schedule a poll to happen, though. + lastTimePolled = Time.Current - TimeBetweenPolls.Value; scheduleNextPoll(); - return false; - } - - private void doPoll() - { - scheduledPoll = null; - pollingActive = true; - Poll().ContinueWith(_ => pollComplete()); } /// @@ -90,13 +64,11 @@ namespace osu.Game.Online return Task.CompletedTask; } - /// - /// Immediately performs a . - /// - public void PollImmediately() + private void doPoll() { - lastTimePolled = Time.Current - TimeBetweenPolls.Value; - scheduleNextPoll(); + scheduledPoll = null; + pollingActive = true; + Poll().ContinueWith(_ => pollComplete()); } /// @@ -111,6 +83,33 @@ namespace osu.Game.Online pollIfNecessary(); } + private void pollIfNecessary() + { + // we must be loaded so we have access to clock. + if (!IsLoaded) return; + + // there's already a poll process running. + if (pollingActive) return; + + // don't try polling if the time between polls hasn't been set. + if (TimeBetweenPolls.Value == 0) return; + + if (!lastTimePolled.HasValue) + { + doPoll(); + return; + } + + if (Time.Current - lastTimePolled.Value > TimeBetweenPolls.Value) + { + doPoll(); + return; + } + + // not enough time has passed since the last poll. we do want to schedule a poll to happen, though. + scheduleNextPoll(); + } + private void scheduleNextPoll() { scheduledPoll?.Cancel(); From 4b198d14eb4dd473cf042c940d0955bbdc69411a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 17:05:20 +0900 Subject: [PATCH 403/961] Initial refactor of RoomSubScreen --- .../Multiplayer/TestSceneMultiplayer.cs | 13 + .../TestSceneMultiplayerMatchSubScreen.cs | 34 +- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 126 +++++-- .../Multiplayer/MultiplayerMatchSubScreen.cs | 349 +++++++++--------- .../Playlists/PlaylistsRoomSubScreen.cs | 8 + 5 files changed, 302 insertions(+), 228 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index e618b28f40..035bdbea1c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -83,6 +83,19 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("load multiplayer", () => LoadScreen(multiplayerScreen)); AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded); AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); } [Test] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index ea10fc1b8b..21364fe154 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -59,23 +59,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for load", () => screen.IsCurrentScreen()); } - [Test] - public void TestSettingValidity() - { - AddAssert("create button not enabled", () => !this.ChildrenOfType().Single().Enabled.Value); - - AddStep("set playlist", () => - { - SelectedRoom.Value.Playlist.Add(new PlaylistItem - { - Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, - Ruleset = { Value = new OsuRuleset().RulesetInfo }, - }); - }); - - AddAssert("create button enabled", () => this.ChildrenOfType().Single().Enabled.Value); - } - [Test] public void TestCreatedRoom() { @@ -97,6 +80,23 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for join", () => Client.Room != null); } + [Test] + public void TestSettingValidity() + { + AddAssert("create button not enabled", () => !this.ChildrenOfType().Single().Enabled.Value); + + AddStep("set playlist", () => + { + SelectedRoom.Value.Playlist.Add(new PlaylistItem + { + Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + }); + }); + + AddAssert("create button enabled", () => this.ChildrenOfType().Single().Enabled.Value); + } + [Test] public void TestStartMatchWhileSpectating() { diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 243d2abf74..8de8e5e897 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -19,6 +19,7 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Match @@ -31,8 +32,6 @@ namespace osu.Game.Screens.OnlinePlay.Match public override bool DisallowExternalBeatmapRulesetChanges => true; - private readonly ModSelectOverlay userModsSelectOverlay; - /// /// A container that provides controls for selection of user mods. /// This will be shown/hidden automatically when applicable. @@ -58,49 +57,106 @@ namespace osu.Game.Screens.OnlinePlay.Match private IBindable> managerUpdated; [Cached] - protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; } + protected OnlinePlayBeatmapAvailabilityTracker BeatmapAvailabilityTracker { get; private set; } protected IBindable BeatmapAvailability => BeatmapAvailabilityTracker.Availability; - protected RoomSubScreen() + private readonly Room room; + + private ModSelectOverlay userModsSelectOverlay; + + protected RoomSubScreen(Room room) { + this.room = room; + Padding = new MarginPadding { Top = Header.HEIGHT }; - AddRangeInternal(new Drawable[] + BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. - }, - BeatmapAvailabilityTracker = new OnlinePlayBeatmapAvailabilityTracker - { - SelectedItem = { BindTarget = SelectedItem } - }, - new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Depth = float.MinValue, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }, - Child = userModsSelectOverlay = new UserModSelectOverlay - { - SelectedMods = { BindTarget = UserMods }, - IsValidMod = _ => false - } - }, - }); + SelectedItem = { BindTarget = SelectedItem } + }; } - protected override void ClearInternal(bool disposeChildren = true) => - throw new InvalidOperationException($"{nameof(RoomSubScreen)}'s children should not be cleared as it will remove required components"); - [BackgroundDependencyLoader] private void load(AudioManager audio) { sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); + + InternalChildren = new Drawable[] + { + BeatmapAvailabilityTracker, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + // Padded main content (drawable room + main content) + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 60 }, + // Main content + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + CreateDrawableRoom(room), + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = 10, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. + }, + }, + CreateMainContent(), + new Container + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = userModsSelectOverlay = new UserModSelectOverlay + { + SelectedMods = { BindTarget = UserMods }, + IsValidMod = _ => false + } + }, + } + } + } + } + } + } + }, + // Footer + new[] + { + CreateFooter() + } + } + } + }; } protected override void LoadComplete() @@ -257,6 +313,12 @@ namespace osu.Game.Screens.OnlinePlay.Match track.Looping = false; } + protected abstract DrawableRoom CreateDrawableRoom(Room room); + + protected abstract Drawable CreateMainContent(); + + protected abstract Drawable CreateFooter(); + private class UserModSelectOverlay : LocalPlayerModSelectOverlay { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 6277afa8bb..da766c9e25 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -22,6 +22,7 @@ using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; @@ -58,10 +59,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [CanBeNull] private IDisposable readyClickOperation; - private GridContainer mainContent; + // private GridContainer mainContent; private MultiplayerMatchSettingsOverlay settingsOverlay; public MultiplayerMatchSubScreen(Room room) + : base(room) { Room = room; @@ -72,191 +74,16 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [BackgroundDependencyLoader] private void load() { - AddRangeInternal(new Drawable[] - { - mainContent = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Horizontal = HORIZONTAL_OVERFLOW_PADDING + 55, - Vertical = 20 - }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - Content = new[] - { - new Drawable[] - { - new MultiplayerMatchHeader - { - OpenSettings = () => settingsOverlay.Show() - } - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), - new Dimension(), - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), - }, - Content = new[] - { - new Drawable[] - { - // Main left column - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] { new ParticipantsListHeader() }, - new Drawable[] - { - new ParticipantsList - { - RelativeSizeAxes = Axes.Both - }, - } - } - }, - // Spacer - null, - // Main right column - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new OverlinedHeader("Beatmap"), - new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } - } - }, - UserModsSection = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 10 }, - Children = new Drawable[] - { - new OverlinedHeader("Extra mods"), - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new UserModSelectButton - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Width = 90, - Text = "Select", - Action = ShowUserModSelect, - }, - new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = UserMods, - Scale = new Vector2(0.8f), - }, - } - } - } - } - } - } - } - } - } - } - }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] { new OverlinedHeader("Chat") }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } - } - } - } - }, - } - } - }, - new Drawable[] - { - new MultiplayerMatchFooter - { - OnReadyClick = onReadyClick, - OnSpectateClick = onSpectateClick - } - } - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - } - }, - settingsOverlay = new MultiplayerMatchSettingsOverlay - { - RelativeSizeAxes = Axes.Both, - State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } - } - }); - if (client.Room == null) { // A new room is being created. // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. - mainContent.Hide(); + // mainContent.Hide(); settingsOverlay.State.BindValueChanged(visibility => { - if (visibility.NewValue == Visibility.Hidden) - mainContent.Show(); + // if (visibility.NewValue == Visibility.Hidden) + // mainContent.Show(); }, true); } } @@ -303,6 +130,170 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); } + protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableRoom(room); + + protected override Drawable CreateMainContent() => new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Horizontal = HORIZONTAL_OVERFLOW_PADDING + 55, + Vertical = 20 + }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] + { + new MultiplayerMatchHeader + { + OpenSettings = () => settingsOverlay.Show() + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), + new Dimension(), + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + }, + Content = new[] + { + new Drawable[] + { + // Main left column + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { new ParticipantsListHeader() }, + new Drawable[] + { + new ParticipantsList + { + RelativeSizeAxes = Axes.Both + }, + } + } + }, + // Spacer + null, + // Main right column + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new OverlinedHeader("Beatmap"), + new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } + } + }, + UserModsSection = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + new OverlinedHeader("Extra mods"), + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new UserModSelectButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 90, + Text = "Select", + Action = ShowUserModSelect, + }, + new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = UserMods, + Scale = new Vector2(0.8f), + }, + } + } + } + } + } + } + } + } + } + } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { new OverlinedHeader("Chat") }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + } + } + } + }, + } + }, + settingsOverlay = new MultiplayerMatchSettingsOverlay + { + RelativeSizeAxes = Axes.Both, + // State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } + } + } + }; + + protected override Drawable CreateFooter() => new MultiplayerMatchFooter + { + OnReadyClick = onReadyClick, + OnSpectateClick = onSpectateClick + }; + [Resolved(canBeNull: true)] private DialogOverlay dialogOverlay { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 682b055766..8ca592ee2c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -14,6 +14,7 @@ using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -45,6 +46,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private SelectionPollingComponent selectionPollingComponent; public PlaylistsRoomSubScreen(Room room) + : base(room) { Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); @@ -295,5 +297,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { Exited = () => leaderboard.RefreshScores() }); + + protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableRoom(room); + + protected override Drawable CreateMainContent() => Empty(); + + protected override Drawable CreateFooter() => Empty(); } } From 6416e64e06a1695d03e3b524a1094de772bae2b3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 17:13:25 +0900 Subject: [PATCH 404/961] Adjust sizings and paddings --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 11 ++++++++++- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 8de8e5e897..7513ffa0f3 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -88,6 +88,11 @@ namespace osu.Game.Screens.OnlinePlay.Match new GridContainer { RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize) + }, Content = new[] { // Padded main content (drawable room + main content) @@ -96,7 +101,11 @@ namespace osu.Game.Screens.OnlinePlay.Match new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 60 }, + Padding = new MarginPadding + { + Horizontal = WaveOverlayContainer.WIDTH_PADDING, + Bottom = 30 + }, // Main content Child = new GridContainer { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index da766c9e25..0a7ddb1254 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -142,8 +142,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Horizontal = HORIZONTAL_OVERFLOW_PADDING + 55, - Vertical = 20 + Horizontal = 10, + Vertical = 10 }, Child = new GridContainer { From 5d72c5911af23537b27addcd5b64e66022d0da40 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 17:14:21 +0900 Subject: [PATCH 405/961] Rename MatchSettingsOverlay and related classes Because "match" is a multiplayer-only concept. --- .../Playlists/TestScenePlaylistsMatchSettingsOverlay.cs | 2 +- .../Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs | 4 ++-- .../{MatchSettingsOverlay.cs => RoomSettingsOverlay.cs} | 2 +- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 +- ...atchSettingsOverlay.cs => PlaylistsRoomSettingsOverlay.cs} | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) rename osu.Game/Screens/OnlinePlay/Match/Components/{MatchSettingsOverlay.cs => RoomSettingsOverlay.cs} (97%) rename osu.Game/Screens/OnlinePlay/Playlists/{PlaylistsMatchSettingsOverlay.cs => PlaylistsRoomSettingsOverlay.cs} (99%) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 98882b659c..04b44efd32 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -110,7 +110,7 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("error not displayed", () => !settings.ErrorText.IsPresent); } - private class TestRoomSettings : PlaylistsMatchSettingsOverlay + private class TestRoomSettings : PlaylistsRoomSettingsOverlay { public TriangleButton ApplyButton => ((MatchSettings)Settings).ApplyButton; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 9fc29049ef..ee93e728ac 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -96,7 +96,7 @@ namespace osu.Game.Tests.Visual.Playlists AddStep("move mouse to create button", () => { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); }); AddStep("click", () => InputManager.Click(MouseButton.Left)); @@ -147,7 +147,7 @@ namespace osu.Game.Tests.Visual.Playlists AddStep("create room", () => { - InputManager.MoveMouseTo(match.ChildrenOfType().Single()); + InputManager.MoveMouseTo(match.ChildrenOfType().Single()); InputManager.Click(MouseButton.Left); }); diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs similarity index 97% rename from osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs rename to osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index 2676453a7e..bcefd5a333 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -14,7 +14,7 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Match.Components { - public abstract class MatchSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler + public abstract class RoomSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler { protected const float TRANSITION_DURATION = 350; protected const float FIELD_PADDING = 45; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 5f3921d742..3a95ac00a6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -26,7 +26,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { - public class MultiplayerMatchSettingsOverlay : MatchSettingsOverlay + public class MultiplayerMatchSettingsOverlay : RoomSettingsOverlay { private MatchSettings settings; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs similarity index 99% rename from osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs rename to osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 2640f99ea5..d28f886be4 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -22,7 +22,7 @@ using osuTK; namespace osu.Game.Screens.OnlinePlay.Playlists { - public class PlaylistsMatchSettingsOverlay : MatchSettingsOverlay + public class PlaylistsRoomSettingsOverlay : RoomSettingsOverlay { public Action EditPlaylist; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 8ca592ee2c..c2f92d7e00 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private readonly IBindable isIdle = new BindableBool(); - private MatchSettingsOverlay settingsOverlay; + private RoomSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; private OverlinedHeader participantsHeader; private GridContainer mainContent; @@ -237,7 +237,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists new Dimension(GridSizeMode.AutoSize), } }, - settingsOverlay = new PlaylistsMatchSettingsOverlay + settingsOverlay = new PlaylistsRoomSettingsOverlay { RelativeSizeAxes = Axes.Both, EditPlaylist = () => From 9eb16fa61de76cd0432cb199503ef9a4f31f6d2c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 17:16:21 +0900 Subject: [PATCH 406/961] Move poll allowance logic based on signalr connection inside polling component --- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 47 +++++++------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index 97fed2040d..d152fc3913 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -25,19 +25,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private MultiplayerClient client { get; set; } - private MultiplayerListingPollingComponent multiplayerListingPollingComponent => (MultiplayerListingPollingComponent)ListingPollingComponent; - - private readonly IBindable isConnected = new Bindable(); - - protected override void LoadComplete() - { - base.LoadComplete(); - - isConnected.BindTo(client.IsConnected); - isConnected.BindValueChanged(c => Scheduler.AddOnce(() => multiplayerListingPollingComponent.AllowPolling = c.NewValue)); - multiplayerListingPollingComponent.AllowPolling = isConnected.Value; - } - public override void OnResuming(IScreen last) { base.OnResuming(last); @@ -47,7 +34,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (last is MultiplayerMatchSubScreen match) { RoomManager.RemoveRoom(match.Room); - multiplayerListingPollingComponent.PollImmediately(); + ListingPollingComponent.PollImmediately(); } } @@ -84,27 +71,29 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private class MultiplayerListingPollingComponent : ListingPollingComponent { - private bool allowPolling; + [Resolved] + private MultiplayerClient client { get; set; } - public bool AllowPolling + private readonly IBindable isConnected = new Bindable(); + + [BackgroundDependencyLoader] + private void load() { - get => allowPolling; - set + isConnected.BindTo(client.IsConnected); + isConnected.BindValueChanged(c => Scheduler.AddOnce(() => { - if (allowPolling == value) - return; - - allowPolling = value; - - if (!allowPolling) - return; - - if (IsLoaded) + if (isConnected.Value && IsLoaded) PollImmediately(); - } + }), true); } - protected override Task Poll() => AllowPolling ? base.Poll() : Task.CompletedTask; + protected override Task Poll() + { + if (!isConnected.Value) + return Task.CompletedTask; + + return base.Poll(); + } } } } From 3b5fc6d10ff17fb06f43cdd107036a6e7da0164a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 17:18:23 +0900 Subject: [PATCH 407/961] Ensure `updateLoadingLayer` is run at least once --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 3e8d07d002..8bed3d6049 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -186,16 +186,16 @@ namespace osu.Game.Screens.OnlinePlay.Lounge searchTextBox.Current.BindValueChanged(_ => updateFilterDebounced()); ruleset.BindValueChanged(_ => UpdateFilter()); - ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer()); - isIdle.BindValueChanged(_ => updatePollingRate(this.IsCurrentScreen()), true); if (ongoingOperationTracker != null) { operationInProgress.BindTo(ongoingOperationTracker.InProgress); - operationInProgress.BindValueChanged(_ => updateLoadingLayer(), true); + operationInProgress.BindValueChanged(_ => updateLoadingLayer()); } + ListingPollingComponent.InitialRoomsReceived.BindValueChanged(_ => updateLoadingLayer(), true); + updateFilter(); } From c0b388cd74e864f6654d161e4bd631ca36408b0c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 17:50:30 +0900 Subject: [PATCH 408/961] Fix regression in `ModSettingsChangeTracker` --- osu.Game/Overlays/Settings/SettingsItem.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index c35690151c..6621caef4e 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -119,19 +119,19 @@ namespace osu.Game.Overlays.Settings }, }, }; - } - [BackgroundDependencyLoader] - private void load() - { - // all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is + // IMPORTANT: all bindable logic is in constructor intentionally to support "CreateSettingsControls" being used in a context it is // never loaded, but requires bindable storage. if (controlWithCurrent == null) throw new ArgumentException(@$"Control created via {nameof(CreateControl)} must implement {nameof(IHasCurrentValue)}"); controlWithCurrent.Current.ValueChanged += _ => SettingChanged?.Invoke(); controlWithCurrent.Current.DisabledChanged += _ => updateDisabled(); + } + [BackgroundDependencyLoader] + private void load() + { // intentionally done before LoadComplete to avoid overhead. if (ShowsDefaultIndicator) { From 6840ec671684501b2ca47675d17e4405fdd7a55e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 17:58:24 +0900 Subject: [PATCH 409/961] Actually show the room in the sub screen --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 7513ffa0f3..afd7112b22 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -113,13 +113,15 @@ namespace osu.Game.Screens.OnlinePlay.Match RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 10) }, Content = new[] { new Drawable[] { - CreateDrawableRoom(room), + CreateDrawableRoom(room).With(d => d.MatchingFilter = true), }, + null, new Drawable[] { new Container From f16468b7063ea85c7b610f0d761151ad181f02f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 18:17:55 +0900 Subject: [PATCH 410/961] Improve visibility of repeat ticks / drag areas on timeline --- .../Timeline/TimelineHitObjectBlueprint.cs | 46 +++++++++---------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs index 6e57b8e88c..911c9fea51 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineHitObjectBlueprint.cs @@ -166,14 +166,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline } if (IsSelected) - { border.Show(); - colour = colour.Lighten(0.3f); - } else - { border.Hide(); - } if (Item is IHasDuration duration && duration.Duration > 0) circle.Colour = ColourInfo.GradientHorizontal(colour, colour.Lighten(0.4f)); @@ -212,14 +207,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline for (int i = 0; i < repeats.RepeatCount; i++) { - repeatsContainer.Add(new Circle + repeatsContainer.Add(new Tick { - Size = new Vector2(circle_size / 3), - Alpha = 0.2f, - Anchor = Anchor.CentreLeft, - Origin = Anchor.Centre, - RelativePositionAxes = Axes.X, - X = (float)(i + 1) / (repeats.RepeatCount + 1), + X = (float)(i + 1) / (repeats.RepeatCount + 1) }); } } @@ -233,6 +223,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline public override Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.TopLeft; + private class Tick : Circle + { + public Tick() + { + Size = new Vector2(circle_size / 4); + Anchor = Anchor.CentreLeft; + Origin = Anchor.Centre; + RelativePositionAxes = Axes.X; + } + } + public class DragArea : Circle { private readonly HitObject hitObject; @@ -304,20 +305,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private void updateState() { - if (hasMouseDown) - { - this.ScaleTo(0.7f, 200, Easing.OutQuint); - } - else if (IsHovered) - { - this.ScaleTo(0.8f, 200, Easing.OutQuint); - } - else - { - this.ScaleTo(0.6f, 200, Easing.OutQuint); - } + float scale = 0.5f; - this.FadeTo(IsHovered || hasMouseDown ? 0.8f : 0.2f, 200, Easing.OutQuint); + if (hasMouseDown) + scale = 0.6f; + else if (IsHovered) + scale = 0.7f; + + this.ScaleTo(scale, 200, Easing.OutQuint); + this.FadeTo(IsHovered || hasMouseDown ? 1f : 0.9f, 200, Easing.OutQuint); } [Resolved] From 590d814881e71dcb4ad353f40e7a5164df8adb41 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 18:24:04 +0900 Subject: [PATCH 411/961] Move RoomSettingsOverlay to RoomSubScreen --- .../Match/Components/RoomSettingsOverlay.cs | 8 +- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 109 ++++++++++++------ .../Multiplayer/MultiplayerMatchSubScreen.cs | 44 +------ .../Playlists/PlaylistsRoomSubScreen.cs | 2 + 4 files changed, 82 insertions(+), 81 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index bcefd5a333..5f0ce0feed 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -27,11 +27,15 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected abstract bool IsLoading { get; } + protected RoomSettingsOverlay() + { + RelativeSizeAxes = Axes.Both; + Masking = true; + } + [BackgroundDependencyLoader] private void load() { - Masking = true; - Add(Settings = CreateSettings()); } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index afd7112b22..a79f9421a7 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -64,6 +64,7 @@ namespace osu.Game.Screens.OnlinePlay.Match private readonly Room room; private ModSelectOverlay userModsSelectOverlay; + private RoomSettingsOverlay settingsOverlay; protected RoomSubScreen(Room room) { @@ -82,6 +83,8 @@ namespace osu.Game.Screens.OnlinePlay.Match { sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); + Drawable mainContent; + InternalChildren = new Drawable[] { BeatmapAvailabilityTracker, @@ -106,59 +109,62 @@ namespace osu.Game.Screens.OnlinePlay.Match Horizontal = WaveOverlayContainer.WIDTH_PADDING, Bottom = 30 }, - // Main content - Child = new GridContainer + Children = new[] { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + mainContent = new GridContainer { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, 10) - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - CreateDrawableRoom(room).With(d => d.MatchingFilter = true), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 10) }, - null, - new Drawable[] + Content = new[] { - new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Children = new[] + CreateDrawableRoom(room).With(d => d.MatchingFilter = true), + }, + null, + new Drawable[] + { + new Container { - new Container + RelativeSizeAxes = Axes.Both, + Children = new[] { - RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = 10, - Child = new Box + new Container { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. + Masking = true, + CornerRadius = 10, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. + }, }, - }, - CreateMainContent(), - new Container - { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Child = userModsSelectOverlay = new UserModSelectOverlay + CreateMainContent(), + new Container { - SelectedMods = { BindTarget = UserMods }, - IsValidMod = _ => false - } - }, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = userModsSelectOverlay = new UserModSelectOverlay + { + SelectedMods = { BindTarget = UserMods }, + IsValidMod = _ => false + } + }, + } } } } - } - } - } + }, + settingsOverlay = CreateRoomSettingsOverlay() + }, + }, }, // Footer new[] @@ -168,6 +174,19 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }; + + if (room.RoomID.Value == null) + { + // A new room is being created. + // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. + mainContent.Hide(); + + settingsOverlay.State.BindValueChanged(visibility => + { + if (visibility.NewValue == Visibility.Hidden) + mainContent.Show(); + }, true); + } } protected override void LoadComplete() @@ -184,12 +203,24 @@ namespace osu.Game.Screens.OnlinePlay.Match public override bool OnBackButton() { + if (room.RoomID.Value == null) + { + // room has not been created yet; exit immediately. + return base.OnBackButton(); + } + if (userModsSelectOverlay.State.Value == Visibility.Visible) { userModsSelectOverlay.Hide(); return true; } + if (settingsOverlay.State.Value == Visibility.Visible) + { + settingsOverlay.Hide(); + return true; + } + return base.OnBackButton(); } @@ -330,6 +361,8 @@ namespace osu.Game.Screens.OnlinePlay.Match protected abstract Drawable CreateFooter(); + protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(); + private class UserModSelectOverlay : LocalPlayerModSelectOverlay { } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 0a7ddb1254..1b9c2092dd 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -60,7 +60,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private IDisposable readyClickOperation; // private GridContainer mainContent; - private MultiplayerMatchSettingsOverlay settingsOverlay; public MultiplayerMatchSubScreen(Room room) : base(room) @@ -71,23 +70,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Activity.Value = new UserActivity.InLobby(room); } - [BackgroundDependencyLoader] - private void load() - { - if (client.Room == null) - { - // A new room is being created. - // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. - // mainContent.Hide(); - - settingsOverlay.State.BindValueChanged(visibility => - { - // if (visibility.NewValue == Visibility.Hidden) - // mainContent.Show(); - }, true); - } - } - protected override void LoadComplete() { base.LoadComplete(); @@ -159,7 +141,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { new MultiplayerMatchHeader { - OpenSettings = () => settingsOverlay.Show() + // OpenSettings = () => settingsOverlay.Show() } }, new Drawable[] @@ -280,11 +262,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, } }, - settingsOverlay = new MultiplayerMatchSettingsOverlay - { - RelativeSizeAxes = Axes.Both, - // State = { Value = client.Room == null ? Visibility.Visible : Visibility.Hidden } - } } }; @@ -294,28 +271,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer OnSpectateClick = onSpectateClick }; + protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new MultiplayerMatchSettingsOverlay(); + [Resolved(canBeNull: true)] private DialogOverlay dialogOverlay { get; set; } private bool exitConfirmed; - public override bool OnBackButton() - { - if (client.Room == null) - { - // room has not been created yet; exit immediately. - return base.OnBackButton(); - } - - if (settingsOverlay.State.Value == Visibility.Visible) - { - settingsOverlay.Hide(); - return true; - } - - return base.OnBackButton(); - } - public override bool OnExiting(IScreen next) { // the room may not be left immediately after a disconnection due to async flow, diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index c2f92d7e00..7af74e7e64 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -303,5 +303,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override Drawable CreateMainContent() => Empty(); protected override Drawable CreateFooter() => Empty(); + + protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new PlaylistsRoomSettingsOverlay(); } } From d66f7cb6b597ce62acd5460771958bfc59c1c97f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Aug 2021 19:21:22 +0900 Subject: [PATCH 412/961] Fix tests by allowing retrieval with files where required --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 16 ++++++++-------- osu.Game/Skinning/SkinManager.cs | 10 ++++++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 8124bd4199..bab8dfc983 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -50,10 +50,10 @@ namespace osu.Game.Tests.Skins.IO var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin", "skinner"), "skin2.osk")); Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(1)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(1)); // the first should be overwritten by the second import. - Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); } finally { @@ -76,10 +76,10 @@ namespace osu.Game.Tests.Skins.IO var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk(string.Empty, string.Empty), "download.osk")); Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(2)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(2)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); } finally { @@ -101,10 +101,10 @@ namespace osu.Game.Tests.Skins.IO var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("test skin v2.1", "skinner"), "skin2.osk")); Assert.That(imported2.ID, Is.Not.EqualTo(imported.ID)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().Count, Is.EqualTo(2)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Count, Is.EqualTo(2)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID)); - Assert.That(osu.Dependencies.Get().GetAllUserSkins().Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).First().Files.First().FileInfoID, Is.EqualTo(imported.Files.First().FileInfoID)); + Assert.That(osu.Dependencies.Get().GetAllUserSkins(true).Last().Files.First().FileInfoID, Is.EqualTo(imported2.Files.First().FileInfoID)); } finally { diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index fca1670419..51aaac1f79 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -95,7 +95,7 @@ namespace osu.Game.Skinning /// A newly allocated list of available . public List GetAllUsableSkins() { - var userSkins = GetAllUserSkins(); + var userSkins = GetAllUserSkins(false); userSkins.Insert(0, DefaultSkin.SkinInfo); userSkins.Insert(1, DefaultLegacySkin.SkinInfo); return userSkins; @@ -105,7 +105,13 @@ namespace osu.Game.Skinning /// Returns a list of all usable s that have been loaded by the user. /// /// A newly allocated list of available . - public List GetAllUserSkins() => ModelStore.Items.Where(s => !s.DeletePending).ToList(); + public List GetAllUserSkins(bool includeFiles = false) + { + if (includeFiles) + return ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList(); + + return ModelStore.Items.Where(s => !s.DeletePending).ToList(); + } public void SelectRandomSkin() { From 47d4a2e97f70de9b1cc307554de19b45eaa3a107 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 17 Aug 2021 20:05:26 +0900 Subject: [PATCH 413/961] Make SettingsOverlay protected --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 10 +++++----- .../Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index a79f9421a7..3addf57048 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.OnlinePlay.Match private readonly Room room; private ModSelectOverlay userModsSelectOverlay; - private RoomSettingsOverlay settingsOverlay; + protected RoomSettingsOverlay SettingsOverlay { get; private set; } protected RoomSubScreen(Room room) { @@ -162,7 +162,7 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }, - settingsOverlay = CreateRoomSettingsOverlay() + SettingsOverlay = CreateRoomSettingsOverlay() }, }, }, @@ -181,7 +181,7 @@ namespace osu.Game.Screens.OnlinePlay.Match // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. mainContent.Hide(); - settingsOverlay.State.BindValueChanged(visibility => + SettingsOverlay.State.BindValueChanged(visibility => { if (visibility.NewValue == Visibility.Hidden) mainContent.Show(); @@ -215,9 +215,9 @@ namespace osu.Game.Screens.OnlinePlay.Match return true; } - if (settingsOverlay.State.Value == Visibility.Visible) + if (SettingsOverlay.State.Value == Visibility.Visible) { - settingsOverlay.Hide(); + SettingsOverlay.Hide(); return true; } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 1b9c2092dd..09c2a22850 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -141,7 +141,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { new MultiplayerMatchHeader { - // OpenSettings = () => settingsOverlay.Show() + OpenSettings = () => SettingsOverlay.Show() } }, new Drawable[] From 2296ee60598cea4d5fb1d276d624d3d54874e312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20Sch=C3=BCrz?= Date: Tue, 17 Aug 2021 16:56:06 +0200 Subject: [PATCH 414/961] Add test coverage --- .../Visual/Editing/TestSceneEditorClock.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs index 0b1617b6a6..0abf0c47f8 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs @@ -78,6 +78,24 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500); } + [Test] + public void TestClampWhenSeekOutsideBeatmapBounds() + { + AddStep("stop clock", Clock.Stop); + + AddStep("seek before start time", () => Clock.Seek(-1000)); + AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0); + + AddStep("seek beyond track length", () => Clock.Seek(Clock.TrackLength + 1000)); + AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength); + + AddStep("seek smoothly before start time", () => Clock.SeekSmoothlyTo(-1000)); + AddAssert("time is clamped to 0", () => Clock.CurrentTime == 0); + + AddStep("seek smoothly beyond track length", () => Clock.SeekSmoothlyTo(Clock.TrackLength + 1000)); + AddAssert("time is clamped to track length", () => Clock.CurrentTime == Clock.TrackLength); + } + protected override void Dispose(bool isDisposing) { Beatmap.Disabled = false; From 58ecee543ad546c7c1e1f91ae6fb1187920f0b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Aug 2021 23:00:10 +0200 Subject: [PATCH 415/961] Trim redundant default argument value --- osu.Game/Skinning/SkinManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 51aaac1f79..0f805990b9 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -95,7 +95,7 @@ namespace osu.Game.Skinning /// A newly allocated list of available . public List GetAllUsableSkins() { - var userSkins = GetAllUserSkins(false); + var userSkins = GetAllUserSkins(); userSkins.Insert(0, DefaultSkin.SkinInfo); userSkins.Insert(1, DefaultLegacySkin.SkinInfo); return userSkins; From eaca331170c8fb7f7303a55fe630c3400d1ddde6 Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Wed, 18 Aug 2021 08:13:53 +0800 Subject: [PATCH 416/961] apply suggestions --- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Users/UserActivity.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 3e7479643e..80be61ead1 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -224,7 +224,7 @@ namespace osu.Game.Rulesets public abstract string ShortName { get; } /// - /// The playing verb to be shown in the . + /// The playing verb to be shown in the activities. /// public virtual string PlayingVerb => "Playing"; diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 1bbe38b416..88b91a3b42 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -25,13 +25,13 @@ namespace osu.Game.Users public override string Status => "Choosing a beatmap"; } - public class InGame : UserActivity + public abstract class InGame : UserActivity { public BeatmapInfo Beatmap { get; } public RulesetInfo Ruleset { get; } - public InGame(BeatmapInfo info, RulesetInfo ruleset) + protected InGame(BeatmapInfo info, RulesetInfo ruleset) { Beatmap = info; Ruleset = ruleset; From 8c5d99ab21c71fe5e1c743835c8b5245c8b17246 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 04:16:57 +0300 Subject: [PATCH 417/961] Override `CreateInstance()` in osu! bindable subclasses Three bindables are left which don't have this overriden due to them already not having a value-only constructor and not supporting `GetBoundCopy()` properly: - `BeatmapDifficultyCache.BindableStarDifficulty`. - `TotalScoreBindable` - `TotalScoreStringBindable` I could add support for them by passing the required data to them, as they seem to be able to have that shared, but I'm hesitant to support something which was already broken and never used, not sure. --- osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs | 2 +- osu.Game/Rulesets/Mods/DifficultyBindable.cs | 2 +- osu.Game/Screens/Edit/BindableBeatDivisor.cs | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 186514e868..3978378c3a 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Mods { // Intercept and extract the internal number bindable from DifficultyBindable. // This will provide bounds and precision specifications for the slider bar. - difficultyBindable = ((DifficultyBindable)value).GetBoundCopy(); + difficultyBindable = (DifficultyBindable)value.GetBoundCopy(); sliderDisplayCurrent.BindTo(difficultyBindable.CurrentNumber); base.Current = difficultyBindable; diff --git a/osu.Game/Rulesets/Mods/DifficultyBindable.cs b/osu.Game/Rulesets/Mods/DifficultyBindable.cs index 664b88eef4..e4304795f2 100644 --- a/osu.Game/Rulesets/Mods/DifficultyBindable.cs +++ b/osu.Game/Rulesets/Mods/DifficultyBindable.cs @@ -128,6 +128,6 @@ namespace osu.Game.Rulesets.Mods ExtendedLimits.UnbindFrom(otherDifficultyBindable.ExtendedLimits); } - public new DifficultyBindable GetBoundCopy() => new DifficultyBindable { BindTarget = this }; + protected override Bindable CreateInstance() => new DifficultyBindable(); } } diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs index ff33f0c70d..dfe2992a7c 100644 --- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs +++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Edit protected override int DefaultMaxValue => VALID_DIVISORS.Last(); protected override int DefaultPrecision => 1; + protected override Bindable CreateInstance() => new BindableBeatDivisor(); + /// /// Retrieves the appropriate colour for a beat divisor. /// From 5671820d92011d83f3d170df01e0f5f07fcc1837 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 10:35:34 +0900 Subject: [PATCH 418/961] 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 ec223f98c2..24d07b4588 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d4dba9330f..928620b32e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 7e514afe74..77f9052e85 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From f5923508564b8d24f3d9ca475c7144aa466b9332 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 04:59:08 +0300 Subject: [PATCH 419/961] Fix config pollution in HUD overlay test scene --- .../Visual/Gameplay/TestSceneHUDOverlay.cs | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 3017428039..4f15032c62 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -19,6 +19,8 @@ namespace osu.Game.Tests.Visual.Gameplay { public class TestSceneHUDOverlay : OsuManualInputManagerTestScene { + private OsuConfigManager localConfig; + private HUDOverlay hudOverlay; [Cached] @@ -31,8 +33,14 @@ namespace osu.Game.Tests.Visual.Gameplay private Drawable hideTarget => hudOverlay.KeyCounter; private FillFlowContainer keyCounterFlow => hudOverlay.KeyCounter.ChildrenOfType>().First(); - [Resolved] - private OsuConfigManager config { get; set; } + [BackgroundDependencyLoader] + private void load() + { + Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage)); + } + + [SetUpSteps] + public void SetUp() => Schedule(() => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always)); [Test] public void TestComboCounterIncrementing() @@ -85,11 +93,7 @@ namespace osu.Game.Tests.Visual.Gameplay { createNew(); - HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay; - - AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); - - AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); AddUntilStep("wait for fade", () => !hideTarget.IsPresent); @@ -98,37 +102,28 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft)); AddUntilStep("wait for fade", () => !hideTarget.IsPresent); - - AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); } [Test] public void TestExternalHideDoesntAffectConfig() { - HUDVisibilityMode originalConfigValue = HUDVisibilityMode.HideDuringGameplay; - createNew(); - AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); - AddStep("set showhud false", () => hudOverlay.ShowHud.Value = false); - AddAssert("config unchanged", () => originalConfigValue == config.Get(OsuSetting.HUDVisibilityMode)); + AddAssert("config unchanged", () => localConfig.GetBindable(OsuSetting.HUDVisibilityMode).IsDefault); AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true); - AddAssert("config unchanged", () => originalConfigValue == config.Get(OsuSetting.HUDVisibilityMode)); + AddAssert("config unchanged", () => localConfig.GetBindable(OsuSetting.HUDVisibilityMode).IsDefault); } [Test] public void TestChangeHUDVisibilityOnHiddenKeyCounter() { - bool keyCounterVisibleValue = false; - createNew(); - AddStep("save keycounter visible value", () => keyCounterVisibleValue = config.Get(OsuSetting.KeyOverlay)); - AddStep("set keycounter visible false", () => + AddStep("hide key overlay", () => { - config.SetValue(OsuSetting.KeyOverlay, false); + localConfig.SetValue(OsuSetting.KeyOverlay, false); hudOverlay.KeyCounter.AlwaysVisible.Value = false; }); @@ -139,24 +134,16 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("set showhud true", () => hudOverlay.ShowHud.Value = true); AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent); AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent); - - AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue)); } [Test] public void TestHiddenHUDDoesntBlockSkinnableComponentsLoad() { - HUDVisibilityMode originalConfigValue = default; - - AddStep("get original config value", () => originalConfigValue = config.Get(OsuSetting.HUDVisibilityMode)); - - AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); + AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); createNew(); AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded); AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); - - AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue)); } private void createNew(Action action = null) @@ -175,5 +162,11 @@ namespace osu.Game.Tests.Visual.Gameplay Child = hudOverlay; }); } + + protected override void Dispose(bool isDisposing) + { + localConfig?.Dispose(); + base.Dispose(isDisposing); + } } } From 1fdaefef99d4b79cba8cbc428fb7d55cd5597cc9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 12:45:08 +0900 Subject: [PATCH 420/961] Revert unnecessary changes --- osu.Game/Overlays/SettingsPanel.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index fea797287e..376e36ea4e 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -180,7 +179,7 @@ namespace osu.Game.Overlays protected override void OnFocus(FocusEvent e) { - searchTextBox?.TakeFocus(); + searchTextBox.TakeFocus(); base.OnFocus(e); } @@ -274,8 +273,6 @@ namespace osu.Game.Overlays { public SearchContainer SearchContainer; - public new ScheduledDelegate Schedule(Action action) => Scheduler.AddDelayed(action, TransformDelay); - protected override FlowContainer CreateScrollContentContainer() => SearchContainer = new SearchContainer { From 5441fab6922bc05344b3797898502742d7d89dda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 12:45:14 +0900 Subject: [PATCH 421/961] Avoid scheduling focus operation when not required --- osu.Game/Graphics/UserInterface/FocusedTextBox.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index 4a42027964..06a40e7245 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -25,7 +25,7 @@ namespace osu.Game.Graphics.UserInterface if (!allowImmediateFocus) return; - Schedule(() => GetContainingInputManager().ChangeFocus(this)); + Scheduler.Add(() => GetContainingInputManager().ChangeFocus(this), false); } public bool HoldFocus From 6ed3e469f7549b0346314d31e606d2ff942e542c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 06:50:01 +0300 Subject: [PATCH 422/961] Fix wrong attribute used for setup method --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 4f15032c62..290ba3317b 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay Dependencies.Cache(localConfig = new OsuConfigManager(LocalStorage)); } - [SetUpSteps] + [SetUp] public void SetUp() => Schedule(() => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always)); [Test] From c66abf85f71d4a755262c805f06bccf7782b54d5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 14:04:44 +0900 Subject: [PATCH 423/961] Remove match header --- .../Match/MultiplayerMatchHeader.cs | 106 ------------------ .../Multiplayer/MultiplayerMatchSubScreen.cs | 14 --- 2 files changed, 120 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs deleted file mode 100644 index bb351d06d3..0000000000 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchHeader.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.API; -using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Users.Drawables; -using osuTK; -using FontWeight = osu.Game.Graphics.FontWeight; -using OsuColour = osu.Game.Graphics.OsuColour; -using OsuFont = osu.Game.Graphics.OsuFont; - -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match -{ - public class MultiplayerMatchHeader : OnlinePlayComposite - { - public const float HEIGHT = 50; - - public Action OpenSettings; - - private UpdateableAvatar avatar; - private LinkFlowContainer hostText; - private Button openSettingsButton; - - [Resolved] - private IAPIProvider api { get; set; } - - public MultiplayerMatchHeader() - { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChildren = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - avatar = new UpdateableAvatar - { - Size = new Vector2(50), - Masking = true, - CornerRadius = 10, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 30), - Current = { BindTarget = RoomName } - }, - hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20)) - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - } - } - } - } - }, - openSettingsButton = new PurpleTriangleButton - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Size = new Vector2(150, HEIGHT), - Text = "Open settings", - Action = () => OpenSettings?.Invoke(), - Alpha = 0 - } - }; - - Host.BindValueChanged(host => - { - avatar.User = host.NewValue; - - hostText.Clear(); - - if (host.NewValue != null) - { - hostText.AddText("hosted by "); - hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); - } - - openSettingsButton.Alpha = host.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0; - }, true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 09c2a22850..93377b221f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -59,8 +59,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [CanBeNull] private IDisposable readyClickOperation; - // private GridContainer mainContent; - public MultiplayerMatchSubScreen(Room room) : base(room) { @@ -130,20 +128,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Child = new GridContainer { RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, Content = new[] { - new Drawable[] - { - new MultiplayerMatchHeader - { - OpenSettings = () => SettingsOverlay.Show() - } - }, new Drawable[] { new Container From 3d88a745cd2f5184e114447c329b89f45ca339ca Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 18 Aug 2021 14:27:05 +0900 Subject: [PATCH 424/961] Fix osu editor transforms not specified in the absolute time --- .../Edit/DrawableOsuEditorRuleset.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs index d4f1602a46..c89527d8bd 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditorRuleset.cs @@ -64,11 +64,14 @@ namespace osu.Game.Rulesets.Osu.Edit if (hitObject is DrawableHitCircle circle) { - circle.ApproachCircle - .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4) - .Expire(); + using (circle.BeginAbsoluteSequence(circle.HitStateUpdateTime)) + { + circle.ApproachCircle + .FadeOutFromOne(EDITOR_HIT_OBJECT_FADE_OUT_EXTENSION * 4) + .Expire(); - circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); + circle.ApproachCircle.ScaleTo(1.1f, 300, Easing.OutQuint); + } } if (hitObject is IHasMainCirclePiece mainPieceContainer) From 0853554c2403700be54db9763466788bd19379f8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:11:52 +0900 Subject: [PATCH 425/961] Fix settings overlay not being initially visible --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 3addf57048..9e729515d2 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -162,7 +162,10 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }, - SettingsOverlay = CreateRoomSettingsOverlay() + SettingsOverlay = CreateRoomSettingsOverlay().With(s => + { + s.State.Value = room.RoomID.Value == null ? Visibility.Visible : Visibility.Hidden; + }) }, }, }, From 704af94d399517093b084809c7144d165f57965c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:12:16 +0900 Subject: [PATCH 426/961] Add edit button to room panel --- .../Lounge/Components/DrawableRoom.cs | 20 ++++--- .../Match/DrawableMultiplayerRoom.cs | 54 +++++++++++++++++++ .../Multiplayer/MultiplayerMatchSubScreen.cs | 5 +- 3 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index c8ecd65574..4e81739dc4 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -124,17 +124,23 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } + public bool FilteringActive { get; set; } + + protected readonly Container ButtonsContainer = new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }; + private readonly Bindable roomCategory = new Bindable(); + private readonly Bindable hasPassword = new Bindable(); private RecentParticipantsList recentParticipantsList; private RoomSpecialCategoryPill specialCategoryPill; - - public bool FilteringActive { get; set; } - private PasswordProtectedIcon passwordIcon; - private readonly Bindable hasPassword = new Bindable(); - public DrawableRoom(Room room) { Room = room; @@ -289,13 +295,15 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Origin = Anchor.CentreRight, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, + Spacing = new Vector2(5), Padding = new MarginPadding { Right = 10, - Vertical = 5 + Vertical = 20, }, Children = new Drawable[] { + ButtonsContainer, recentParticipantsList = new RecentParticipantsList { Anchor = Anchor.CentreRight, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs new file mode 100644 index 0000000000..84ae6108f6 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Online.API; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match +{ + public class DrawableMultiplayerRoom : DrawableRoom + { + public Action OnEdit; + + [Resolved] + private IAPIProvider api { get; set; } + + private readonly IBindable host = new Bindable(); + + private Drawable editButton; + + public DrawableMultiplayerRoom(Room room) + : base(room) + { + host.BindTo(room.Host); + } + + [BackgroundDependencyLoader] + private void load() + { + ButtonsContainer.Add(editButton = new PurpleTriangleButton + { + RelativeSizeAxes = Axes.Y, + Size = new Vector2(100, 1), + Text = "Edit", + Action = () => OnEdit?.Invoke() + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); + } + + protected override bool ShouldBeConsideredForInput(Drawable child) => true; + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 93377b221f..3cbc6c36b6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -110,7 +110,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); } - protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableRoom(room); + protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableMultiplayerRoom(room) + { + OnEdit = () => SettingsOverlay.Show() + }; protected override Drawable CreateMainContent() => new Container { From 1ae4a1910a135a8c1084d332bbf2650fa13abdf2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 09:17:42 +0300 Subject: [PATCH 427/961] Cache mod settings rather than fetching everytime --- osu.Game/Rulesets/Mods/Mod.cs | 36 +++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index a99ddc6924..8c2a8a8e8b 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; @@ -129,6 +130,17 @@ namespace osu.Game.Rulesets.Mods [JsonIgnore] public virtual Type[] IncompatibleMods => Array.Empty(); + private IReadOnlyList settingsBacking; + + /// + /// A list of the all settings within this mod. + /// + internal IReadOnlyList Settings => + settingsBacking ??= this.GetSettingsSourceProperties() + .Select(p => p.Item2.GetValue(this)) + .Cast() + .ToList(); + /// /// Creates a copy of this initialised to a default state. /// @@ -191,10 +203,7 @@ namespace osu.Game.Rulesets.Mods if (ReferenceEquals(this, other)) return true; return GetType() == other.GetType() && - this.GetSettingsSourceProperties().All(pair => - EqualityComparer.Default.Equals( - ModUtils.GetSettingUnderlyingValue(pair.Item2.GetValue(this)), - ModUtils.GetSettingUnderlyingValue(pair.Item2.GetValue(other)))); + Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default); } public override int GetHashCode() @@ -203,8 +212,8 @@ namespace osu.Game.Rulesets.Mods hashCode.Add(GetType()); - foreach (var (_, prop) in this.GetSettingsSourceProperties()) - hashCode.Add(ModUtils.GetSettingUnderlyingValue(prop.GetValue(this))); + foreach (var setting in Settings) + hashCode.Add(ModUtils.GetSettingUnderlyingValue(setting)); return hashCode.ToHashCode(); } @@ -213,5 +222,20 @@ namespace osu.Game.Rulesets.Mods /// Reset all custom settings for this mod back to their defaults. /// public virtual void ResetSettingsToDefaults() => CopyFrom((Mod)Activator.CreateInstance(GetType())); + + private class ModSettingsEqualityComparer : IEqualityComparer + { + public static ModSettingsEqualityComparer Default { get; } = new ModSettingsEqualityComparer(); + + public bool Equals(IBindable x, IBindable y) + { + object xValue = x == null ? null : ModUtils.GetSettingUnderlyingValue(x); + object yValue = y == null ? null : ModUtils.GetSettingUnderlyingValue(y); + + return EqualityComparer.Default.Equals(xValue, yValue); + } + + public int GetHashCode(IBindable obj) => ModUtils.GetSettingUnderlyingValue(obj).GetHashCode(); + } } } From 96b6670d1fe2e3018acdfe8ee0dd98a0981b5f6f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 09:18:03 +0300 Subject: [PATCH 428/961] Add mod benchmark --- osu.Game.Benchmarks/BenchmarkMod.cs | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 osu.Game.Benchmarks/BenchmarkMod.cs diff --git a/osu.Game.Benchmarks/BenchmarkMod.cs b/osu.Game.Benchmarks/BenchmarkMod.cs new file mode 100644 index 0000000000..050ddf36d5 --- /dev/null +++ b/osu.Game.Benchmarks/BenchmarkMod.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using BenchmarkDotNet.Attributes; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Benchmarks +{ + public class BenchmarkMod : BenchmarkTest + { + private OsuModDoubleTime mod; + + [Params(1, 10, 100)] + public int Times { get; set; } + + [GlobalSetup] + public void GlobalSetup() + { + mod = new OsuModDoubleTime(); + } + + [Benchmark] + public int ModHashCode() + { + var hashCode = new HashCode(); + + for (int i = 0; i < Times; i++) + hashCode.Add(mod); + + return hashCode.ToHashCode(); + } + } +} From c5268c9a99d820d16534fc912e15cd02a1d08894 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:16:48 +0900 Subject: [PATCH 429/961] Simplify by reusing same room panel --- .../DrawableMatchRoom.cs} | 6 +++--- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 19 ++++++++++--------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 6 ------ .../Playlists/PlaylistsRoomSubScreen.cs | 3 --- 4 files changed, 13 insertions(+), 21 deletions(-) rename osu.Game/Screens/OnlinePlay/{Multiplayer/Match/DrawableMultiplayerRoom.cs => Match/DrawableMatchRoom.cs} (89%) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs similarity index 89% rename from osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs rename to osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index 84ae6108f6..f7b4dd6920 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/DrawableMultiplayerRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -12,9 +12,9 @@ using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Users; using osuTK; -namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match +namespace osu.Game.Screens.OnlinePlay.Match { - public class DrawableMultiplayerRoom : DrawableRoom + public class DrawableMatchRoom : DrawableRoom { public Action OnEdit; @@ -25,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private Drawable editButton; - public DrawableMultiplayerRoom(Room room) + public DrawableMatchRoom(Room room) : base(room) { host.BindTo(room.Host); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 9e729515d2..8dc5c0cc4a 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -19,7 +19,6 @@ using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Screens.OnlinePlay.Match @@ -64,7 +63,7 @@ namespace osu.Game.Screens.OnlinePlay.Match private readonly Room room; private ModSelectOverlay userModsSelectOverlay; - protected RoomSettingsOverlay SettingsOverlay { get; private set; } + private RoomSettingsOverlay settingsOverlay; protected RoomSubScreen(Room room) { @@ -123,7 +122,11 @@ namespace osu.Game.Screens.OnlinePlay.Match { new Drawable[] { - CreateDrawableRoom(room).With(d => d.MatchingFilter = true), + new DrawableMatchRoom(room) + { + MatchingFilter = true, + OnEdit = () => settingsOverlay.Show() + } }, null, new Drawable[] @@ -162,7 +165,7 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }, - SettingsOverlay = CreateRoomSettingsOverlay().With(s => + settingsOverlay = CreateRoomSettingsOverlay().With(s => { s.State.Value = room.RoomID.Value == null ? Visibility.Visible : Visibility.Hidden; }) @@ -184,7 +187,7 @@ namespace osu.Game.Screens.OnlinePlay.Match // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. mainContent.Hide(); - SettingsOverlay.State.BindValueChanged(visibility => + settingsOverlay.State.BindValueChanged(visibility => { if (visibility.NewValue == Visibility.Hidden) mainContent.Show(); @@ -218,9 +221,9 @@ namespace osu.Game.Screens.OnlinePlay.Match return true; } - if (SettingsOverlay.State.Value == Visibility.Visible) + if (settingsOverlay.State.Value == Visibility.Visible) { - SettingsOverlay.Hide(); + settingsOverlay.Hide(); return true; } @@ -358,8 +361,6 @@ namespace osu.Game.Screens.OnlinePlay.Match track.Looping = false; } - protected abstract DrawableRoom CreateDrawableRoom(Room room); - protected abstract Drawable CreateMainContent(); protected abstract Drawable CreateFooter(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 3cbc6c36b6..73c8053c1a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -22,7 +22,6 @@ using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; @@ -110,11 +109,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); } - protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableMultiplayerRoom(room) - { - OnEdit = () => SettingsOverlay.Show() - }; - protected override Drawable CreateMainContent() => new Container { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 7af74e7e64..c655f49820 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -14,7 +14,6 @@ using osu.Game.Input; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -298,8 +297,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Exited = () => leaderboard.RefreshScores() }); - protected override DrawableRoom CreateDrawableRoom(Room room) => new DrawableRoom(room); - protected override Drawable CreateMainContent() => Empty(); protected override Drawable CreateFooter() => Empty(); From 228ad98b39ad6056eb387ed9e478b4de92db02fa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:27:23 +0900 Subject: [PATCH 430/961] Remove extra corner radius on DrawableRoom --- osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 4e81739dc4..b627dfbb8e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -149,7 +149,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Height = height; Masking = true; - CornerRadius = corner_radius + SELECTION_BORDER_WIDTH / 2; + CornerRadius = corner_radius; EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, From 744b6749d18ca282ba3eb6426b950ecd5cb071e7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:29:01 +0900 Subject: [PATCH 431/961] Resolve room settings layout issues --- .../Match/Components/RoomSettingsOverlay.cs | 3 +++ osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index eec512347b..86687d7da8 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -31,6 +31,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { RelativeSizeAxes = Axes.Both; Masking = true; + CornerRadius = 10; } [BackgroundDependencyLoader] @@ -47,12 +48,14 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { base.PopIn(); Settings.MoveToY(0, TRANSITION_DURATION, Easing.OutQuint); + Settings.FadeIn(TRANSITION_DURATION / 2); } protected override void PopOut() { base.PopOut(); Settings.MoveToY(-1, TRANSITION_DURATION, Easing.InSine); + Settings.Delay(TRANSITION_DURATION / 2).FadeOut(TRANSITION_DURATION / 2); } public bool OnPressed(GlobalAction action) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 8dc5c0cc4a..9c7b255213 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -165,10 +165,16 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }, - settingsOverlay = CreateRoomSettingsOverlay().With(s => + new Container { - s.State.Value = room.RoomID.Value == null ? Visibility.Visible : Visibility.Hidden; - }) + RelativeSizeAxes = Axes.Both, + // Resolves 1px masking errors between the settings overlay and the room panel. + Padding = new MarginPadding(-1), + Child = settingsOverlay = CreateRoomSettingsOverlay().With(s => + { + s.State.Value = room.RoomID.Value == null ? Visibility.Visible : Visibility.Hidden; + }) + } }, }, }, From 90a1be2e6158b2f2cb7bdb6533d0fa22e77056aa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 15:54:33 +0900 Subject: [PATCH 432/961] Move paddings up one level --- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 7 +- .../Multiplayer/MultiplayerMatchSubScreen.cs | 216 ++++++++---------- 2 files changed, 106 insertions(+), 117 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 9c7b255213..8e6cfe2acb 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -147,7 +147,12 @@ namespace osu.Game.Screens.OnlinePlay.Match Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. }, }, - CreateMainContent(), + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(10), + Child = CreateMainContent(), + }, new Container { Anchor = Anchor.BottomLeft, diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 73c8053c1a..b9bcb27d60 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -109,115 +109,99 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); } - protected override Drawable CreateMainContent() => new Container + protected override Drawable CreateMainContent() => new GridContainer { RelativeSizeAxes = Axes.Both, - Children = new Drawable[] + Content = new[] { - new Container + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Horizontal = 10, - Vertical = 10 - }, - Child = new GridContainer + new Container { RelativeSizeAxes = Axes.Both, - Content = new[] + Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, + Child = new GridContainer { - new Drawable[] + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - new Container + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), + new Dimension(), + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + }, + Content = new[] + { + new Drawable[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 5, Vertical = 10 }, - Child = new GridContainer + // Main left column + new GridContainer { RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + RowDimensions = new[] { - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), - new Dimension(), - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + new Dimension(GridSizeMode.AutoSize) }, Content = new[] { + new Drawable[] { new ParticipantsListHeader() }, new Drawable[] { - // Main left column - new GridContainer + new ParticipantsList { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] { new ParticipantsListHeader() }, - new Drawable[] - { - new ParticipantsList - { - RelativeSizeAxes = Axes.Both - }, - } - } + RelativeSizeAxes = Axes.Both }, - // Spacer - null, - // Main right column - new FillFlowContainer + } + } + }, + // Spacer + null, + // Main right column + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new[] + new OverlinedHeader("Beatmap"), + new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } + } + }, + UserModsSection = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Top = 10 }, + Children = new Drawable[] + { + new OverlinedHeader("Extra mods"), + new FillFlowContainer { - new FillFlowContainer + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + new UserModSelectButton { - new OverlinedHeader("Beatmap"), - new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } - } - }, - UserModsSection = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 10 }, - Children = new Drawable[] + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 90, + Text = "Select", + Action = ShowUserModSelect, + }, + new ModDisplay { - new OverlinedHeader("Extra mods"), - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new UserModSelectButton - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Width = 90, - Text = "Select", - Action = ShowUserModSelect, - }, - new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = UserMods, - Scale = new Vector2(0.8f), - }, - } - } - } + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = UserMods, + Scale = new Vector2(0.8f), + }, } } } @@ -225,27 +209,27 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } } } - }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] { new OverlinedHeader("Chat") }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } - } - } } - }, + } } }, - } + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize) + }, + Content = new[] + { + new Drawable[] { new OverlinedHeader("Chat") }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + } + } + } + }, }; protected override Drawable CreateFooter() => new MultiplayerMatchFooter @@ -444,19 +428,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } } - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (client != null) - { - client.RoomUpdated -= onRoomUpdated; - client.LoadRequested -= onLoadRequested; - } - - modSettingChangeTracker?.Dispose(); - } - public void PresentBeatmap(WorkingBeatmap beatmap, RulesetInfo ruleset) { if (!this.IsCurrentScreen()) @@ -472,5 +443,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer this.Push(new MultiplayerMatchSongSelect(beatmap, ruleset)); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (client != null) + { + client.RoomUpdated -= onRoomUpdated; + client.LoadRequested -= onLoadRequested; + } + + modSettingChangeTracker?.Dispose(); + } } } From dc44cc0eb34783f306437bd90716c914ec7c0174 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 15:32:59 +0900 Subject: [PATCH 433/961] Update scenarios to use new `TestRunHeadlessGameHost` where feasible --- .../Collections/IO/ImportCollectionsTest.cs | 5 +++-- .../NonVisual/CustomDataDirectoryTest.cs | 15 ++++++++++++--- osu.Game/Tests/CleanRunHeadlessGameHost.cs | 4 ++-- osu.Game/Tests/Visual/OsuTestScene.cs | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index 8f5ebf53bd..d87ac29d75 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Tests.Resources; namespace osu.Game.Tests.Collections.IO @@ -127,7 +128,7 @@ namespace osu.Game.Tests.Collections.IO [Test] public async Task TestSaveAndReload() { - using (HeadlessGameHost host = new CleanRunHeadlessGameHost()) + using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload", bypassCleanup: true)) { try { @@ -148,7 +149,7 @@ namespace osu.Game.Tests.Collections.IO } } - using (HeadlessGameHost host = new HeadlessGameHost("TestSaveAndReload")) + using (HeadlessGameHost host = new TestRunHeadlessGameHost("TestSaveAndReload")) { try { diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs index 4c44e2ec72..c9f5774735 100644 --- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs +++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs @@ -6,10 +6,10 @@ using System.IO; using System.Linq; using System.Runtime.CompilerServices; using NUnit.Framework; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.IO; @@ -278,7 +278,7 @@ namespace osu.Game.Tests.NonVisual private static string getDefaultLocationFor(string testTypeName) { - string path = Path.Combine(RuntimeInfo.StartupDirectory, "headless", testTypeName); + string path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, testTypeName); if (Directory.Exists(path)) Directory.Delete(path, true); @@ -288,7 +288,7 @@ namespace osu.Game.Tests.NonVisual private string prepareCustomPath(string suffix = "") { - string path = Path.Combine(RuntimeInfo.StartupDirectory, $"custom-path{suffix}"); + string path = Path.Combine(TestRunHeadlessGameHost.TemporaryTestDirectory, $"custom-path{suffix}"); if (Directory.Exists(path)) Directory.Delete(path, true); @@ -308,6 +308,15 @@ namespace osu.Game.Tests.NonVisual InitialStorage = new DesktopStorage(defaultStorageLocation, this); InitialStorage.DeleteDirectory(string.Empty); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + // the storage may have changed from the initial location. + // this handles cleanup of the initial location. + InitialStorage.DeleteDirectory(string.Empty); + } } } } diff --git a/osu.Game/Tests/CleanRunHeadlessGameHost.cs b/osu.Game/Tests/CleanRunHeadlessGameHost.cs index 03ab94d1da..d7ab769ac4 100644 --- a/osu.Game/Tests/CleanRunHeadlessGameHost.cs +++ b/osu.Game/Tests/CleanRunHeadlessGameHost.cs @@ -2,14 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System.Runtime.CompilerServices; -using osu.Framework.Platform; +using osu.Framework.Testing; namespace osu.Game.Tests { /// /// A headless host which cleans up before running (removing any remnants from a previous execution). /// - public class CleanRunHeadlessGameHost : HeadlessGameHost + public class CleanRunHeadlessGameHost : TestRunHeadlessGameHost { /// /// Create a new instance. diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 57e400a77e..ef1a35ffa5 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -155,7 +155,7 @@ namespace osu.Game.Tests.Visual } localStorage = - new Lazy(() => isolatedHostStorage ?? new NativeStorage(Path.Combine(RuntimeInfo.StartupDirectory, $"{GetType().Name}-{Guid.NewGuid()}"))); + new Lazy(() => isolatedHostStorage ?? new TemporaryNativeStorage($"{GetType().Name}-{Guid.NewGuid()}")); } [Resolved] From 568f1fd345fd7f51660623c90916036aa84dbdce Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 16:09:00 +0900 Subject: [PATCH 434/961] Fix initial RoomId state not being handled correctly --- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 49 ++++++++++--------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 -- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 8e6cfe2acb..ae92ab92c1 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -44,6 +44,8 @@ namespace osu.Game.Screens.OnlinePlay.Match /// protected readonly Bindable> UserMods = new Bindable>(Array.Empty()); + protected readonly IBindable RoomId = new Bindable(); + [Resolved] private MusicController music { get; set; } @@ -60,14 +62,15 @@ namespace osu.Game.Screens.OnlinePlay.Match protected IBindable BeatmapAvailability => BeatmapAvailabilityTracker.Availability; - private readonly Room room; + public readonly Room Room; private ModSelectOverlay userModsSelectOverlay; private RoomSettingsOverlay settingsOverlay; + private Drawable mainContent; protected RoomSubScreen(Room room) { - this.room = room; + Room = room; Padding = new MarginPadding { Top = Header.HEIGHT }; @@ -75,6 +78,8 @@ namespace osu.Game.Screens.OnlinePlay.Match { SelectedItem = { BindTarget = SelectedItem } }; + + RoomId.BindTo(room.RoomID); } [BackgroundDependencyLoader] @@ -82,8 +87,6 @@ namespace osu.Game.Screens.OnlinePlay.Match { sampleStart = audio.Samples.Get(@"SongSelect/confirm-selection"); - Drawable mainContent; - InternalChildren = new Drawable[] { BeatmapAvailabilityTracker, @@ -122,7 +125,7 @@ namespace osu.Game.Screens.OnlinePlay.Match { new Drawable[] { - new DrawableMatchRoom(room) + new DrawableMatchRoom(Room) { MatchingFilter = true, OnEdit = () => settingsOverlay.Show() @@ -175,10 +178,7 @@ namespace osu.Game.Screens.OnlinePlay.Match RelativeSizeAxes = Axes.Both, // Resolves 1px masking errors between the settings overlay and the room panel. Padding = new MarginPadding(-1), - Child = settingsOverlay = CreateRoomSettingsOverlay().With(s => - { - s.State.Value = room.RoomID.Value == null ? Visibility.Visible : Visibility.Hidden; - }) + Child = settingsOverlay = CreateRoomSettingsOverlay() } }, }, @@ -191,25 +191,28 @@ namespace osu.Game.Screens.OnlinePlay.Match } } }; - - if (room.RoomID.Value == null) - { - // A new room is being created. - // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. - mainContent.Hide(); - - settingsOverlay.State.BindValueChanged(visibility => - { - if (visibility.NewValue == Visibility.Hidden) - mainContent.Show(); - }, true); - } } protected override void LoadComplete() { base.LoadComplete(); + RoomId.BindValueChanged(id => + { + if (id.NewValue == null) + { + // A new room is being created. + // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. + mainContent.Hide(); + settingsOverlay.Show(); + } + else + { + mainContent.Show(); + settingsOverlay.Hide(); + } + }, true); + SelectedItem.BindValueChanged(_ => Scheduler.AddOnce(selectedItemChanged)); managerUpdated = beatmapManager.ItemUpdated.GetBoundCopy(); @@ -220,7 +223,7 @@ namespace osu.Game.Screens.OnlinePlay.Match public override bool OnBackButton() { - if (room.RoomID.Value == null) + if (Room.RoomID.Value == null) { // room has not been created yet; exit immediately. return base.OnBackButton(); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index b9bcb27d60..f8e5d7d901 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -42,8 +42,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override string ShortTitle => "room"; - public readonly Room Room; - [Resolved] private MultiplayerClient client { get; set; } @@ -61,8 +59,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public MultiplayerMatchSubScreen(Room room) : base(room) { - Room = room; - Title = room.RoomID.Value == null ? "New room" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); } From 66e11fe75eb0424af82fc03c384d372df7304fc2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 16:09:15 +0900 Subject: [PATCH 435/961] Initial integration of playlists with the new structure --- .../Playlists/PlaylistsRoomSubScreen.cs | 390 ++++++++---------- 1 file changed, 166 insertions(+), 224 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index c655f49820..bf0107d3c3 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -30,18 +30,13 @@ namespace osu.Game.Screens.OnlinePlay.Playlists public override string ShortTitle => "playlist"; - [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } - - [Resolved(typeof(Room), nameof(Room.Playlist))] - private BindableList playlist { get; set; } + [Resolved] + private IAPIProvider api { get; set; } private readonly IBindable isIdle = new BindableBool(); - private RoomSettingsOverlay settingsOverlay; private MatchLeaderboard leaderboard; private OverlinedHeader participantsHeader; - private GridContainer mainContent; private SelectionPollingComponent selectionPollingComponent; public PlaylistsRoomSubScreen(Room room) @@ -57,231 +52,21 @@ namespace osu.Game.Screens.OnlinePlay.Playlists if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); - AddRangeInternal(new Drawable[] - { - selectionPollingComponent = new SelectionPollingComponent(), - mainContent = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Horizontal = 105, - Vertical = 20 - }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, - Content = new[] - { - new Drawable[] { new Match.Components.Header() }, - new Drawable[] - { - participantsHeader = new OverlinedHeader("Participants") - { - ShowLine = false - } - }, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 5 }, - Child = new ParticipantsDisplay(Direction.Horizontal) - { - Details = { BindTarget = participantsHeader.Details } - } - } - }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 5 }, - Child = new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] { new OverlinedPlaylistHeader(), }, - new Drawable[] - { - new DrawableRoomPlaylistWithResults - { - RelativeSizeAxes = Axes.Both, - Items = { BindTarget = playlist }, - SelectedItem = { BindTarget = SelectedItem }, - RequestShowResults = item => - { - Debug.Assert(roomId.Value != null); - ParentScreen?.Push(new PlaylistsResultsScreen(null, roomId.Value.Value, item, false)); - } - } - }, - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - } - } - }, - null, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new[] - { - UserModsSection = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Bottom = 10 }, - Children = new Drawable[] - { - new OverlinedHeader("Extra mods"), - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new UserModSelectButton - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Width = 90, - Text = "Select", - Action = ShowUserModSelect, - }, - new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = UserMods, - Scale = new Vector2(0.8f), - }, - } - } - } - }, - }, - new Drawable[] - { - new OverlinedHeader("Leaderboard") - }, - new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, - new Drawable[] { new OverlinedHeader("Chat"), }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120), - } - }, - null - }, - }, - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), - new Dimension(), - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), - new Dimension(), - } - } - } - }, - } - } - }, - new Drawable[] - { - new Footer { OnStart = StartPlay } - } - }, - RowDimensions = new[] - { - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - } - }, - settingsOverlay = new PlaylistsRoomSettingsOverlay - { - RelativeSizeAxes = Axes.Both, - EditPlaylist = () => - { - if (this.IsCurrentScreen()) - this.Push(new PlaylistsSongSelect()); - }, - State = { Value = roomId.Value == null ? Visibility.Visible : Visibility.Hidden } - } - }); - - if (roomId.Value == null) - { - // A new room is being created. - // The main content should be hidden until the settings overlay is hidden, signaling the room is ready to be displayed. - mainContent.Hide(); - - settingsOverlay.State.BindValueChanged(visibility => - { - if (visibility.NewValue == Visibility.Hidden) - mainContent.Show(); - }, true); - } + AddInternal(selectionPollingComponent = new SelectionPollingComponent()); } - [Resolved] - private IAPIProvider api { get; set; } - protected override void LoadComplete() { base.LoadComplete(); isIdle.BindValueChanged(_ => updatePollingRate(), true); - - roomId.BindValueChanged(id => + RoomId.BindValueChanged(id => { - if (id.NewValue == null) - settingsOverlay.Show(); - else + if (id.NewValue != null) { - settingsOverlay.Hide(); - // Set the first playlist item. // This is scheduled since updating the room and playlist may happen in an arbitrary order (via Room.CopyFrom()). - Schedule(() => SelectedItem.Value = playlist.FirstOrDefault()); + Schedule(() => SelectedItem.Value = Room.Playlist.FirstOrDefault()); } }, true); } @@ -297,10 +82,167 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Exited = () => leaderboard.RefreshScores() }); - protected override Drawable CreateMainContent() => Empty(); + protected override Drawable CreateMainContent() => new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] { new Match.Components.Header() }, + new Drawable[] + { + participantsHeader = new OverlinedHeader("Participants") + { + ShowLine = false + } + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Top = 5 }, + Child = new ParticipantsDisplay(Direction.Horizontal) + { + Details = { BindTarget = participantsHeader.Details } + } + } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 5 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] { new OverlinedPlaylistHeader(), }, + new Drawable[] + { + new DrawableRoomPlaylistWithResults + { + RelativeSizeAxes = Axes.Both, + Items = { BindTarget = Room.Playlist }, + SelectedItem = { BindTarget = SelectedItem }, + RequestShowResults = item => + { + Debug.Assert(RoomId.Value != null); + ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false)); + } + } + }, + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + } + } + }, + null, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new[] + { + UserModsSection = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = 10 }, + Children = new Drawable[] + { + new OverlinedHeader("Extra mods"), + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + new UserModSelectButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 90, + Text = "Select", + Action = ShowUserModSelect, + }, + new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = UserMods, + Scale = new Vector2(0.8f), + }, + } + } + } + }, + }, + new Drawable[] + { + new OverlinedHeader("Leaderboard") + }, + new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, + new Drawable[] { new OverlinedHeader("Chat"), }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120), + } + }, + null + }, + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), + new Dimension(), + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + new Dimension(), + } + } + } + }, + }; - protected override Drawable CreateFooter() => Empty(); + protected override Drawable CreateFooter() => new Footer + { + OnStart = StartPlay + }; - protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new PlaylistsRoomSettingsOverlay(); + protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new PlaylistsRoomSettingsOverlay + { + EditPlaylist = () => + { + if (this.IsCurrentScreen()) + this.Push(new PlaylistsSongSelect()); + }, + }; } } From 87a5922f0eef0eb69becbdf3a1ea1b12d3ceb501 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 16:26:45 +0900 Subject: [PATCH 436/961] Remove participants from playlists screen --- .../Playlists/PlaylistsRoomSubScreen.cs | 193 +++++++----------- 1 file changed, 76 insertions(+), 117 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index bf0107d3c3..d799f09972 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -36,7 +36,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private readonly IBindable isIdle = new BindableBool(); private MatchLeaderboard leaderboard; - private OverlinedHeader participantsHeader; private SelectionPollingComponent selectionPollingComponent; public PlaylistsRoomSubScreen(Room room) @@ -85,150 +84,110 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override Drawable CreateMainContent() => new GridContainer { RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }, Content = new[] { - new Drawable[] { new Match.Components.Header() }, - new Drawable[] - { - participantsHeader = new OverlinedHeader("Participants") - { - ShowLine = false - } - }, new Drawable[] { new Container { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 5 }, - Child = new ParticipantsDisplay(Direction.Horizontal) + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding { Right = 5 }, + Child = new GridContainer { - Details = { BindTarget = participantsHeader.Details } + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] { new OverlinedPlaylistHeader(), }, + new Drawable[] + { + new DrawableRoomPlaylistWithResults + { + RelativeSizeAxes = Axes.Both, + Items = { BindTarget = Room.Playlist }, + SelectedItem = { BindTarget = SelectedItem }, + RequestShowResults = item => + { + Debug.Assert(RoomId.Value != null); + ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false)); + } + } + }, + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + } } - } - }, - new Drawable[] - { + }, + null, new GridContainer { RelativeSizeAxes = Axes.Both, Content = new[] { - new Drawable[] + new[] { - new Container + UserModsSection = new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Right = 5 }, - Child = new GridContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = 10 }, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new OverlinedHeader("Extra mods"), + new FillFlowContainer { - new Drawable[] { new OverlinedPlaylistHeader(), }, - new Drawable[] + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] { - new DrawableRoomPlaylistWithResults + new UserModSelectButton { - RelativeSizeAxes = Axes.Both, - Items = { BindTarget = Room.Playlist }, - SelectedItem = { BindTarget = SelectedItem }, - RequestShowResults = item => - { - Debug.Assert(RoomId.Value != null); - ParentScreen?.Push(new PlaylistsResultsScreen(null, RoomId.Value.Value, item, false)); - } - } - }, - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 90, + Text = "Select", + Action = ShowUserModSelect, + }, + new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = UserMods, + Scale = new Vector2(0.8f), + }, + } } } }, - null, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new[] - { - UserModsSection = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Bottom = 10 }, - Children = new Drawable[] - { - new OverlinedHeader("Extra mods"), - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - new UserModSelectButton - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Width = 90, - Text = "Select", - Action = ShowUserModSelect, - }, - new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = UserMods, - Scale = new Vector2(0.8f), - }, - } - } - } - }, - }, - new Drawable[] - { - new OverlinedHeader("Leaderboard") - }, - new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, - new Drawable[] { new OverlinedHeader("Chat"), }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } - }, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120), - } - }, - null }, + new Drawable[] + { + new OverlinedHeader("Leaderboard") + }, + new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, + new Drawable[] { new OverlinedHeader("Chat"), }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } }, - ColumnDimensions = new[] + RowDimensions = new[] { - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), - new Dimension(), - new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Relative, size: 0.4f, minSize: 120), } - } - } + }, + }, }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 400), + new Dimension(), + new Dimension(GridSizeMode.Relative, size: 0.5f, maxSize: 600), + } }; protected override Drawable CreateFooter() => new Footer From 2758a83d5556cbea8e4d7b95977b053b8dcb6702 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 16:23:02 +0900 Subject: [PATCH 437/961] Fix `TestSettingsMigration`'s usage of `RecycleLocalStorage` --- .../Input/ConfineMouseTrackerTest.cs | 2 +- .../Menus/TestSceneMusicActionHandling.cs | 1 - .../Visual/Menus/TestSceneSideOverlays.cs | 1 - .../Visual/Navigation/OsuGameTestScene.cs | 9 +++++- .../Visual/Navigation/TestSceneOsuGame.cs | 32 ++++++++++++------- .../Navigation/TestSettingsMigration.cs | 7 ++-- .../TestSceneBeatmapRecommendations.cs | 1 - osu.Game/Tests/Visual/OsuTestScene.cs | 7 ++-- 8 files changed, 37 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs index 27cece42e8..b612899d79 100644 --- a/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs +++ b/osu.Game.Tests/Input/ConfineMouseTrackerTest.cs @@ -8,7 +8,7 @@ using osu.Framework.Input; using osu.Framework.Testing; using osu.Game.Configuration; using osu.Game.Input; -using osu.Game.Tests.Visual.Navigation; +using osu.Game.Tests.Visual; namespace osu.Game.Tests.Input { diff --git a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs index aaf3323432..9037338e23 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneMusicActionHandling.cs @@ -10,7 +10,6 @@ using osu.Game.Database; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osu.Game.Tests.Resources; -using osu.Game.Tests.Visual.Navigation; namespace osu.Game.Tests.Visual.Menus { diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index e58f85b0b3..5230e026bc 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -4,7 +4,6 @@ using NUnit.Framework; using osu.Framework.Testing; using osu.Game.Overlays; -using osu.Game.Tests.Visual.Navigation; namespace osu.Game.Tests.Visual.Menus { diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs index c9a1471e41..e392301568 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs @@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Navigation Game.Dispose(); } - RecycleLocalStorage(); + RecycleLocalStorage(false); CreateGame(); }); @@ -73,6 +73,13 @@ namespace osu.Game.Tests.Visual.Navigation ConfirmAtMainMenu(); } + [TearDownSteps] + public void TearDownSteps() + { + AddStep("exit game", () => Game.Exit()); + AddUntilStep("wait for game exit", () => Game.Parent == null); + } + protected void CreateGame() { Game = new TestOsuGame(LocalStorage, API); diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index 26641214b1..48e68b03fb 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -88,25 +89,32 @@ namespace osu.Game.Tests.Visual.Navigation [Resolved] private OsuGameBase gameBase { get; set; } - [BackgroundDependencyLoader] - private void load(GameHost host) - { - game = new OsuGame(); - game.SetHost(host); + [Resolved] + private GameHost host { get; set; } - Children = new Drawable[] + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create game", () => { - new Box + game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + }); AddUntilStep("wait for load", () => game.IsLoaded); } + [Test] public void TestNullRulesetHandled() { diff --git a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs index c1c968e862..7e3d8290be 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSettingsMigration.cs @@ -9,9 +9,12 @@ namespace osu.Game.Tests.Visual.Navigation { public class TestSettingsMigration : OsuGameTestScene { - public override void RecycleLocalStorage() + public override void RecycleLocalStorage(bool isDisposing) { - base.RecycleLocalStorage(); + base.RecycleLocalStorage(isDisposing); + + if (isDisposing) + return; using (var config = new OsuConfigManager(LocalStorage)) { diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs index 5e2d5eba5d..53cb628bb3 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapRecommendations.cs @@ -14,7 +14,6 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; -using osu.Game.Tests.Visual.Navigation; using osu.Game.Users; namespace osu.Game.Tests.Visual.SongSelect diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index ef1a35ffa5..ef9181c8a6 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -7,7 +7,6 @@ using System.IO; using System.Linq; using System.Threading.Tasks; using JetBrains.Annotations; -using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Track; @@ -100,7 +99,7 @@ namespace osu.Game.Tests.Visual return factory; }); - RecycleLocalStorage(); + RecycleLocalStorage(false); var baseDependencies = base.CreateChildDependencies(parent); @@ -140,7 +139,7 @@ namespace osu.Game.Tests.Visual protected virtual bool UseFreshStoragePerRun => false; - public virtual void RecycleLocalStorage() + public virtual void RecycleLocalStorage(bool isDisposing) { if (localStorage?.IsValueCreated == true) { @@ -199,7 +198,7 @@ namespace osu.Game.Tests.Visual if (contextFactory?.IsValueCreated == true) contextFactory.Value.ResetDatabase(); - RecycleLocalStorage(); + RecycleLocalStorage(true); } protected override ITestSceneTestRunner CreateRunner() => new OsuTestSceneTestRunner(); From 4725b802b017c19ecb31c9526a49e544f33377be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 16:38:54 +0900 Subject: [PATCH 438/961] Share `OsuGameTestScene` with implementations across template projects --- .../TestSceneOsuGame.cs | 23 +----------- .../TestSceneOsuGame.cs | 23 +----------- .../TestSceneOsuGame.cs | 23 +----------- .../TestSceneOsuGame.cs | 23 +----------- .../Visual/Navigation/TestSceneOsuGame.cs | 37 +------------------ .../Tests/Visual}/OsuGameTestScene.cs | 7 +--- 6 files changed, 7 insertions(+), 129 deletions(-) rename {osu.Game.Tests/Visual/Navigation => osu.Game/Tests/Visual}/OsuGameTestScene.cs (93%) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs index 9c512a01ea..fb63f69f72 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs @@ -1,32 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Platform; using osu.Game.Tests.Visual; -using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyFreeform.Tests { - public class TestSceneOsuGame : OsuTestScene + public class TestSceneOsuGame : OsuGameTestScene { - [BackgroundDependencyLoader] - private void load(GameHost host, OsuGameBase gameBase) - { - OsuGame game = new OsuGame(); - game.SetHost(host); - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; - } } } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index 270d906b01..a99a400afa 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -1,32 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Platform; using osu.Game.Tests.Visual; -using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuTestScene + public class TestSceneOsuGame : OsuGameTestScene { - [BackgroundDependencyLoader] - private void load(GameHost host, OsuGameBase gameBase) - { - OsuGame game = new OsuGame(); - game.SetHost(host); - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; - } } } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs index aed6abb6bf..debdc14b57 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs @@ -1,32 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Platform; using osu.Game.Tests.Visual; -using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyScrolling.Tests { - public class TestSceneOsuGame : OsuTestScene + public class TestSceneOsuGame : OsuGameTestScene { - [BackgroundDependencyLoader] - private void load(GameHost host, OsuGameBase gameBase) - { - OsuGame game = new OsuGame(); - game.SetHost(host); - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; - } } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index 270d906b01..a99a400afa 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -1,32 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; -using osu.Framework.Platform; using osu.Game.Tests.Visual; -using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuTestScene + public class TestSceneOsuGame : OsuGameTestScene { - [BackgroundDependencyLoader] - private void load(GameHost host, OsuGameBase gameBase) - { - OsuGame game = new OsuGame(); - game.SetHost(host); - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; - } } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index 48e68b03fb..d3f1a852d1 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -6,11 +6,7 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; -using osu.Framework.Platform; -using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -28,12 +24,11 @@ using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Skinning; using osu.Game.Utils; -using osuTK.Graphics; namespace osu.Game.Tests.Visual.Navigation { [TestFixture] - public class TestSceneOsuGame : OsuTestScene + public class TestSceneOsuGame : OsuGameTestScene { private IReadOnlyList requiredGameDependencies => new[] { @@ -84,37 +79,9 @@ namespace osu.Game.Tests.Visual.Navigation typeof(PreviewTrackManager), }; - private OsuGame game; - [Resolved] private OsuGameBase gameBase { get; set; } - [Resolved] - private GameHost host { get; set; } - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("create game", () => - { - game = new OsuGame(); - game.SetHost(host); - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - game - }; - }); - - AddUntilStep("wait for load", () => game.IsLoaded); - } - - [Test] public void TestNullRulesetHandled() { @@ -150,7 +117,7 @@ namespace osu.Game.Tests.Visual.Navigation { foreach (var type in requiredGameDependencies) { - if (game.Dependencies.Get(type) == null) + if (Game.Dependencies.Get(type) == null) throw new InvalidOperationException($"{type} has not been cached"); } diff --git a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs similarity index 93% rename from osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs rename to osu.Game/Tests/Visual/OsuGameTestScene.cs index e392301568..f38aaa9358 100644 --- a/osu.Game.Tests/Visual/Navigation/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -22,9 +22,8 @@ using osu.Game.Scoring; using osu.Game.Screens; using osu.Game.Screens.Menu; using osuTK.Graphics; -using IntroSequence = osu.Game.Configuration.IntroSequence; -namespace osu.Game.Tests.Visual.Navigation +namespace osu.Game.Tests.Visual { /// /// A scene which tests full game flow. @@ -85,10 +84,6 @@ namespace osu.Game.Tests.Visual.Navigation Game = new TestOsuGame(LocalStorage, API); Game.SetHost(host); - // todo: this can be removed once we can run audio tracks without a device present - // see https://github.com/ppy/osu/issues/1302 - Game.LocalConfig.SetValue(OsuSetting.IntroSequence, IntroSequence.Circles); - Add(Game); } From 6dc96fdb830b78dc11e539ebeb24b20e7619b615 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 16:35:18 +0900 Subject: [PATCH 439/961] Disable edit button in playlists --- .../TestScenePlaylistsRoomSubScreen.cs | 7 +++-- .../OnlinePlay/Match/DrawableMatchRoom.cs | 26 +++++++++++++------ .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 11 ++++++-- .../Playlists/PlaylistsRoomSubScreen.cs | 2 +- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index ee93e728ac..b8df90be2b 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -19,7 +19,6 @@ using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps; using osu.Game.Tests.Visual.OnlinePlay; -using osu.Game.Users; using osuTK.Input; namespace osu.Game.Tests.Visual.Playlists @@ -66,7 +65,7 @@ namespace osu.Game.Tests.Visual.Playlists { SelectedRoom.Value.RoomID.Value = 1; SelectedRoom.Value.Name.Value = "my awesome room"; - SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" }; + SelectedRoom.Value.Host.Value = API.LocalUser.Value; SelectedRoom.Value.RecentParticipants.Add(SelectedRoom.Value.Host.Value); SelectedRoom.Value.EndDate.Value = DateTimeOffset.Now.AddMinutes(5); SelectedRoom.Value.Playlist.Add(new PlaylistItem @@ -86,7 +85,7 @@ namespace osu.Game.Tests.Visual.Playlists AddStep("set room properties", () => { SelectedRoom.Value.Name.Value = "my awesome room"; - SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" }; + SelectedRoom.Value.Host.Value = API.LocalUser.Value; SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, @@ -137,7 +136,7 @@ namespace osu.Game.Tests.Visual.Playlists AddStep("load room", () => { SelectedRoom.Value.Name.Value = "my awesome room"; - SelectedRoom.Value.Host.Value = new User { Id = 2, Username = "peppy" }; + SelectedRoom.Value.Host.Value = API.LocalUser.Value; SelectedRoom.Value.Playlist.Add(new PlaylistItem { Beatmap = { Value = importedSet.Beatmaps[0] }, diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index f7b4dd6920..ead219bee2 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -22,31 +23,40 @@ namespace osu.Game.Screens.OnlinePlay.Match private IAPIProvider api { get; set; } private readonly IBindable host = new Bindable(); + private readonly bool allowEdit; + [CanBeNull] private Drawable editButton; - public DrawableMatchRoom(Room room) + public DrawableMatchRoom(Room room, bool allowEdit = true) : base(room) { + this.allowEdit = allowEdit; + host.BindTo(room.Host); } [BackgroundDependencyLoader] private void load() { - ButtonsContainer.Add(editButton = new PurpleTriangleButton + if (allowEdit) { - RelativeSizeAxes = Axes.Y, - Size = new Vector2(100, 1), - Text = "Edit", - Action = () => OnEdit?.Invoke() - }); + ButtonsContainer.Add(editButton = new PurpleTriangleButton + { + RelativeSizeAxes = Axes.Y, + Size = new Vector2(100, 1), + Text = "Edit", + Action = () => OnEdit?.Invoke() + }); + } } protected override void LoadComplete() { base.LoadComplete(); - host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); + + if (editButton != null) + host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); } protected override bool ShouldBeConsideredForInput(Drawable child) => true; diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index ae92ab92c1..e95b4b221e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -63,14 +63,21 @@ namespace osu.Game.Screens.OnlinePlay.Match protected IBindable BeatmapAvailability => BeatmapAvailabilityTracker.Availability; public readonly Room Room; + private readonly bool allowEdit; private ModSelectOverlay userModsSelectOverlay; private RoomSettingsOverlay settingsOverlay; private Drawable mainContent; - protected RoomSubScreen(Room room) + /// + /// Creates a new . + /// + /// The . + /// Whether to allow editing room settings post-creation. + protected RoomSubScreen(Room room, bool allowEdit = true) { Room = room; + this.allowEdit = allowEdit; Padding = new MarginPadding { Top = Header.HEIGHT }; @@ -125,7 +132,7 @@ namespace osu.Game.Screens.OnlinePlay.Match { new Drawable[] { - new DrawableMatchRoom(Room) + new DrawableMatchRoom(Room, allowEdit) { MatchingFilter = true, OnEdit = () => settingsOverlay.Show() diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index d799f09972..9855d1cb95 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -39,7 +39,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists private SelectionPollingComponent selectionPollingComponent; public PlaylistsRoomSubScreen(Room room) - : base(room) + : base(room, false) // Editing is temporarily not allowed. { Title = room.RoomID.Value == null ? "New playlist" : room.Name.Value; Activity.Value = new UserActivity.InLobby(room); From 5faf2df9b459bd00d669ff13db6d1f93a412a8d4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 16:42:49 +0900 Subject: [PATCH 440/961] Revert unintentional change --- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 035bdbea1c..e618b28f40 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -83,19 +83,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("load multiplayer", () => LoadScreen(multiplayerScreen)); AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded); AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - - createRoom(() => new Room - { - Name = { Value = "Test Room" }, - Playlist = - { - new PlaylistItem - { - Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, - Ruleset = { Value = new OsuRuleset().RulesetInfo }, - } - } - }); } [Test] From 74d6c2652023e2f603c053ded54bac6b768aa551 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 11:03:35 +0300 Subject: [PATCH 441/961] Refactor star rating display layout with flexibility in mind --- .../TestSceneStarRatingDisplay.cs | 11 ++-- .../Beatmaps/Drawables/StarRatingDisplay.cs | 63 ++++++++++++++----- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index a8bc5664f3..7883049df2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -8,17 +8,15 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; -using osu.Game.Graphics.Containers; using osuTK; namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneStarRatingDisplay : OsuTestScene { - [TestCase(52f, 20f)] - [TestCase(52f, 16f)] - [TestCase(50f, 14f)] - public void TestDisplay(float width, float height) + [TestCase(StarRatingDisplaySize.Regular)] + [TestCase(StarRatingDisplaySize.Small)] + public void TestDisplay(StarRatingDisplaySize size) { AddStep("load displays", () => { @@ -36,11 +34,10 @@ namespace osu.Game.Tests.Visual.UserInterface AutoSizeAxes = Axes.Both, Spacing = new Vector2(2f), Direction = FillDirection.Vertical, - ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i * (i >= 11 ? 25f : 1f) + j * 0.1f, 0)) + ChildrenEnumerable = Enumerable.Range(0, 10).Select(j => new StarRatingDisplay(new StarDifficulty(i * (i >= 11 ? 25f : 1f) + j * 0.1f, 0), size) { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(width, height), }), }) }; diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 2c40aebbe1..ed2fee23d5 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -44,40 +44,63 @@ namespace osu.Game.Beatmaps.Drawables /// Creates a new using an already computed . /// /// The already computed to display. - public StarRatingDisplay(StarDifficulty starDifficulty) + /// The size of the star rating display. + public StarRatingDisplay(StarDifficulty starDifficulty, StarRatingDisplaySize size = StarRatingDisplaySize.Regular) { Current.Value = starDifficulty; - Size = new Vector2(52f, 20f); + AutoSizeAxes = Axes.Both; InternalChild = new CircularContainer { Masking = true, - RelativeSizeAxes = Axes.Both, + AutoSizeAxes = Axes.Both, Children = new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both, }, - starIcon = new SpriteIcon + new GridContainer { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Margin = new MarginPadding { Right = 30f }, - Icon = FontAwesome.Solid.Star, - Size = new Vector2(8f), + AutoSizeAxes = Axes.Both, + Margin = size == StarRatingDisplaySize.Small + ? new MarginPadding { Horizontal = 7f } + : new MarginPadding { Horizontal = 8f, Vertical = 2f }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 3f), + new Dimension(GridSizeMode.AutoSize, minSize: 25f), + }, + RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }, + Content = new[] + { + new[] + { + starIcon = new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Icon = FontAwesome.Solid.Star, + Size = new Vector2(8f), + }, + Empty(), + starsText = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Bottom = 1.5f }, + // todo: this should be size: 12f, but to match up with the design, it needs to be 14.4f + // see https://github.com/ppy/osu-framework/issues/3271. + Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold), + Shadow = false, + } + } + } }, - starsText = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Margin = new MarginPadding { Left = 10f, Bottom = 2f }, - // todo: this should be size: 12f, but to match up with the design, it needs to be 14.4f - // see https://github.com/ppy/osu-framework/issues/3271. - Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold), - Shadow = false, - } } }; } @@ -97,4 +120,10 @@ namespace osu.Game.Beatmaps.Drawables }, true); } } + + public enum StarRatingDisplaySize + { + Small, + Regular, + } } From 9220d17202fb032110d7804a29ae109e5520692f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 17:28:20 +0900 Subject: [PATCH 442/961] Adjust paddings/spacings --- .../Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs | 2 +- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- .../OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index 86687d7da8..80a22880d4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -17,7 +17,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components public abstract class RoomSettingsOverlay : FocusedOverlayContainer, IKeyBindingHandler { protected const float TRANSITION_DURATION = 350; - protected const float FIELD_PADDING = 45; + protected const float FIELD_PADDING = 25; protected OnlinePlayComposite Settings { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index e95b4b221e..e1412c894c 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -160,7 +160,7 @@ namespace osu.Game.Screens.OnlinePlay.Match new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(10), + Padding = new MarginPadding(20), Child = CreateMainContent(), }, new Container diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index d28f886be4..3eea59006a 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -193,7 +193,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Child = new GridContainer { RelativeSizeAxes = Axes.X, - Height = 500, + Height = 448, Content = new[] { new Drawable[] From 209929844414101678998d6c3fa63b61dd9acf5e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 17:30:50 +0900 Subject: [PATCH 443/961] Disallow clicking on chat textbox during gameplay --- .../Multiplayer/TestSceneGameplayChatDisplay.cs | 14 ++++++++++++++ .../OnlinePlay/Multiplayer/GameplayChatDisplay.cs | 2 ++ 2 files changed, 16 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index 795963a1ba..ffbc75ae15 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -49,6 +49,20 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("expand", () => chatDisplay.Expanded.Value = true); } + [Test] + public void TestCantClickWhenPlaying() + { + setLocalUserPlaying(true); + + AddStep("attempt focus chat", () => + { + InputManager.MoveMouseTo(textBox); + InputManager.Click(MouseButton.Left); + }); + + assertChatFocused(false); + } + [Test] public void TestFocusDroppedWhenPlaying() { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 40da8d0a84..6a2609480e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -18,6 +18,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private IBindable localUserPlaying = new Bindable(); + public override bool PropagatePositionalInputSubTree => !localUserPlaying.Value; + public Bindable Expanded = new Bindable(); private const float height = 100; From 5e91ec73e3bf888f5aaf305478d5fceb317106ec Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 11:36:27 +0300 Subject: [PATCH 444/961] Handle star rating range display sizing --- .../Beatmaps/Drawables/StarRatingDisplay.cs | 22 ++++++++++++++++--- .../Components/StarRatingRangeDisplay.cs | 4 ++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index ed2fee23d5..192ebe79d7 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -51,6 +51,23 @@ namespace osu.Game.Beatmaps.Drawables AutoSizeAxes = Axes.Both; + MarginPadding margin = default; + + switch (size) + { + case StarRatingDisplaySize.Small: + margin = new MarginPadding { Horizontal = 7f }; + break; + + case StarRatingDisplaySize.Range: + margin = new MarginPadding { Horizontal = 8f }; + break; + + case StarRatingDisplaySize.Regular: + margin = new MarginPadding { Horizontal = 8f, Vertical = 2f }; + break; + } + InternalChild = new CircularContainer { Masking = true, @@ -66,9 +83,7 @@ namespace osu.Game.Beatmaps.Drawables Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, - Margin = size == StarRatingDisplaySize.Small - ? new MarginPadding { Horizontal = 7f } - : new MarginPadding { Horizontal = 8f, Vertical = 2f }, + Margin = margin, ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), @@ -124,6 +139,7 @@ namespace osu.Game.Beatmaps.Drawables public enum StarRatingDisplaySize { Small, + Range, Regular, } } diff --git a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs index 8e62153225..7b14acf924 100644 --- a/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Components/StarRatingRangeDisplay.cs @@ -64,8 +64,8 @@ namespace osu.Game.Screens.OnlinePlay.Components AutoSizeAxes = Axes.Both, Children = new Drawable[] { - minDisplay = new StarRatingDisplay(default) { Size = new Vector2(52f, 16f) }, - maxDisplay = new StarRatingDisplay(default) { Size = new Vector2(52f, 16f) } + minDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Range), + maxDisplay = new StarRatingDisplay(default, StarRatingDisplaySize.Range) } } }; From d2df09432f040d29ae08a92b2104c8d4fca5eda2 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 11:49:33 +0300 Subject: [PATCH 445/961] Center the star rating display text rather than left --- osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 192ebe79d7..25cde5fb82 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -105,8 +105,8 @@ namespace osu.Game.Beatmaps.Drawables Empty(), starsText = new OsuSpriteText { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, Margin = new MarginPadding { Bottom = 1.5f }, // todo: this should be size: 12f, but to match up with the design, it needs to be 14.4f // see https://github.com/ppy/osu-framework/issues/3271. From 365c1bccc67764695e940006176ab1b676eedee0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 18:24:19 +0900 Subject: [PATCH 446/961] Fix multiplayer channel being unintentionally left after gameplay session --- .../OnlinePlay/Match/Components/MatchChatDisplay.cs | 9 +++++++-- .../OnlinePlay/Multiplayer/GameplayChatDisplay.cs | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index a96d64cb5d..5f960c1b5c 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -19,9 +19,12 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components [Resolved(CanBeNull = true)] private ChannelManager channelManager { get; set; } - public MatchChatDisplay() + private readonly bool leaveChannelOnDispose; + + public MatchChatDisplay(bool leaveChannelOnDispose = true) : base(true) { + this.leaveChannelOnDispose = leaveChannelOnDispose; } protected override void LoadComplete() @@ -42,7 +45,9 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - channelManager?.LeaveChannel(Channel.Value); + + if (leaveChannelOnDispose) + channelManager?.LeaveChannel(Channel.Value); } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 6a2609480e..94542fb804 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer private const float height = 100; public GameplayChatDisplay() + : base(leaveChannelOnDispose: false) { RelativeSizeAxes = Axes.X; From 1faf789f0e70a9d8b7431f127c3a1e76ebf18942 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 18:25:21 +0900 Subject: [PATCH 447/961] Allow expanding chat using key binding even when it is hidden --- .../TestSceneGameplayChatDisplay.cs | 17 ++++++- osu.Game/Online/Chat/StandAloneChatDisplay.cs | 11 +++- .../Multiplayer/GameplayChatDisplay.cs | 50 +++++++++++++------ 3 files changed, 61 insertions(+), 17 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index ffbc75ae15..51960680d6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -83,13 +83,28 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestFocusOnTabKey() + public void TestFocusOnTabKeyWhenExpanded() { assertChatFocused(false); AddStep("press tab", () => InputManager.Key(Key.Tab)); assertChatFocused(true); } + [Test] + public void TestFocusOnTabKeyWhenNotExpanded() + { + AddStep("set not expanded", () => chatDisplay.Expanded.Value = false); + AddUntilStep("is not visible", () => !chatDisplay.IsPresent); + + AddStep("press tab", () => InputManager.Key(Key.Tab)); + assertChatFocused(true); + AddUntilStep("is visible", () => chatDisplay.IsPresent); + + AddStep("press enter", () => InputManager.Key(Key.Enter)); + assertChatFocused(false); + AddUntilStep("is not visible", () => !chatDisplay.IsPresent); + } + private void assertChatFocused(bool isFocused) => AddAssert($"chat {(isFocused ? "focused" : "not focused")}", () => textBox.HasFocus == isFocused); diff --git a/osu.Game/Online/Chat/StandAloneChatDisplay.cs b/osu.Game/Online/Chat/StandAloneChatDisplay.cs index 9d23a089df..6ed2055e65 100644 --- a/osu.Game/Online/Chat/StandAloneChatDisplay.cs +++ b/osu.Game/Online/Chat/StandAloneChatDisplay.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Chat; @@ -22,7 +23,7 @@ namespace osu.Game.Online.Chat { public readonly Bindable Channel = new Bindable(); - protected readonly FocusedTextBox Textbox; + protected readonly ChatTextBox Textbox; protected ChannelManager ChannelManager; @@ -121,6 +122,14 @@ namespace osu.Game.Online.Chat BackgroundUnfocused = new Color4(10, 10, 10, 10); BackgroundFocused = new Color4(10, 10, 10, 255); } + + protected override void OnFocusLost(FocusLostEvent e) + { + base.OnFocusLost(e); + FocusLost?.Invoke(); + } + + public Action FocusLost; } public class StandAloneDrawableChannel : DrawableChannel diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 94542fb804..5d494379e6 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -22,28 +22,20 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public Bindable Expanded = new Bindable(); + private readonly Bindable expandedFromTextboxFocus = new Bindable(); + private const float height = 100; + public override bool PropagateNonPositionalInputSubTree => true; + public GameplayChatDisplay() : base(leaveChannelOnDispose: false) { RelativeSizeAxes = Axes.X; Background.Alpha = 0.2f; - } - private void expandedChanged(ValueChangedEvent expanded) - { - if (expanded.NewValue) - { - this.FadeIn(300, Easing.OutQuint); - this.ResizeHeightTo(height, 500, Easing.OutQuint); - } - else - { - this.FadeOut(300, Easing.OutQuint); - this.ResizeHeightTo(0, 500, Easing.OutQuint); - } + Textbox.FocusLost = () => expandedFromTextboxFocus.Value = false; } protected override void LoadComplete() @@ -61,7 +53,18 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Textbox.ReleaseFocusOnCommit = playing.NewValue; }, true); - Expanded.BindValueChanged(expandedChanged, true); + Expanded.BindValueChanged(_ => updateExpandedState(), true); + expandedFromTextboxFocus.BindValueChanged(focus => + { + if (focus.NewValue) + updateExpandedState(); + else + { + // on finishing typing a message there should be a brief delay before hiding. + using (BeginDelayedSequence(600)) + updateExpandedState(); + } + }, true); } public bool OnPressed(GlobalAction action) @@ -69,7 +72,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer switch (action) { case GlobalAction.FocusChatInput: - Textbox.TakeFocus(); + expandedFromTextboxFocus.Value = true; + + // schedule required to ensure the textbox has become present from above bindable update. + Schedule(() => Textbox.TakeFocus()); return true; } @@ -79,5 +85,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public void OnReleased(GlobalAction action) { } + + private void updateExpandedState() + { + if (Expanded.Value || expandedFromTextboxFocus.Value) + { + this.FadeIn(300, Easing.OutQuint); + this.ResizeHeightTo(height, 500, Easing.OutQuint); + } + else + { + this.FadeOut(300, Easing.OutQuint); + this.ResizeHeightTo(0, 500, Easing.OutQuint); + } + } } } From 28e2b6cec7cff82d007d44a7aa2026ff0679ed73 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Aug 2021 18:34:09 +0900 Subject: [PATCH 448/961] Add transform test for fun --- .../TestSceneStarRatingDisplay.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 7883049df2..052251d5a8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -3,6 +3,7 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; @@ -44,6 +45,31 @@ namespace osu.Game.Tests.Visual.UserInterface }); } + [Test] + public void TestSpectrum() + { + StarRatingDisplay starRating = null; + + BindableDouble starRatingNumeric; + + AddStep("load display", () => + { + Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1)) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(3f), + }; + }); + + AddStep("transform over spectrum", () => + { + starRatingNumeric = new BindableDouble(); + starRatingNumeric.BindValueChanged(val => starRating.Current.Value = new StarDifficulty(val.NewValue, 1)); + this.TransformBindableTo(starRatingNumeric, 10, 10000, Easing.OutQuint); + }); + } + [Test] public void TestChangingStarRatingDisplay() { From 8172ffc401a5ff0abe8a779cc7fd2dba8aee3448 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 18 Aug 2021 13:12:58 +0300 Subject: [PATCH 449/961] Fix lounge sub screen loading layer displaying in the background --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 8bed3d6049..24aad8c124 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -84,7 +84,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter), - loadingLayer = new LoadingLayer(true), new Container { RelativeSizeAxes = Axes.Both, @@ -162,6 +161,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Filter = { BindTarget = filter } } }, + loadingLayer = new LoadingLayer(true), } }, } From 63af67f61b5a69918b34ae7f4dc764deffa7b747 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 20:21:29 +0900 Subject: [PATCH 450/961] Cleanup around footers --- .../Multiplayer/TestSceneMatchHeader.cs | 55 ------------- .../OnlinePlay/Match/Components/Footer.cs | 48 ----------- .../OnlinePlay/Match/Components/Header.cs | 79 ------------------- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 29 ++++++- .../Match/MultiplayerMatchFooter.cs | 63 ++++++--------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 22 +++--- .../Playlists/PlaylistsRoomFooter.cs | 32 ++++++++ .../Playlists/PlaylistsRoomSubScreen.cs | 25 +++--- 8 files changed, 103 insertions(+), 250 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs delete mode 100644 osu.Game/Screens/OnlinePlay/Match/Components/Header.cs create mode 100644 osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs deleted file mode 100644 index 71ba5db481..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Game.Beatmaps; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets.Osu; -using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Tests.Visual.OnlinePlay; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneMatchHeader : OnlinePlayTestScene - { - [SetUp] - public new void Setup() => Schedule(() => - { - SelectedRoom.Value = new Room - { - Name = { Value = "A very awesome room" }, - Host = { Value = new User { Id = 2, Username = "peppy" } }, - Playlist = - { - new PlaylistItem - { - Beatmap = - { - Value = new BeatmapInfo - { - Metadata = new BeatmapMetadata - { - Title = "Title", - Artist = "Artist", - AuthorString = "Author", - }, - Version = "Version", - Ruleset = new OsuRuleset().RulesetInfo - } - }, - RequiredMods = - { - new OsuModDoubleTime(), - new OsuModNoFail(), - new OsuModRelax(), - } - } - } - }; - - Child = new Header(); - }); - } -} diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs deleted file mode 100644 index e91c46beed..0000000000 --- a/osu.Game/Screens/OnlinePlay/Match/Components/Footer.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osu.Game.Screens.OnlinePlay.Playlists; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Match.Components -{ - public class Footer : CompositeDrawable - { - public const float HEIGHT = 50; - - public Action OnStart; - - private readonly Drawable background; - - public Footer() - { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; - - InternalChildren = new[] - { - background = new Box { RelativeSizeAxes = Axes.Both }, - new PlaylistsReadyButton - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(600, 50), - Action = () => OnStart?.Invoke() - } - }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = Color4Extensions.FromHex(@"28242d"); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs b/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs deleted file mode 100644 index a2d11c54c1..0000000000 --- a/osu.Game/Screens/OnlinePlay/Match/Components/Header.cs +++ /dev/null @@ -1,79 +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.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Users.Drawables; -using osuTK; - -namespace osu.Game.Screens.OnlinePlay.Match.Components -{ - public class Header : OnlinePlayComposite - { - public const float HEIGHT = 50; - - private UpdateableAvatar avatar; - private LinkFlowContainer hostText; - - public Header() - { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - avatar = new UpdateableAvatar - { - Size = new Vector2(50), - Masking = true, - CornerRadius = 10, - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 30), - Current = { BindTarget = RoomName } - }, - hostText = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 20)) - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - } - } - } - } - }; - - Host.BindValueChanged(host => - { - avatar.User = host.NewValue; - - hostText.Clear(); - - if (host.NewValue != null) - { - hostText.AddText("hosted by "); - hostText.AddUserLink(host.NewValue, s => s.Font = s.Font.With(weight: FontWeight.SemiBold)); - } - }, true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index e1412c894c..42d76e5a15 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.OnlinePlay.Match RowDimensions = new[] { new Dimension(), - new Dimension(GridSizeMode.AutoSize) + new Dimension(GridSizeMode.Absolute, 50) }, Content = new[] { @@ -154,7 +154,7 @@ namespace osu.Game.Screens.OnlinePlay.Match Child = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex(@"3e3a44") // This is super temporary. + Colour = Color4Extensions.FromHex(@"3e3a44") // Temporary. }, }, new Container @@ -191,9 +191,21 @@ namespace osu.Game.Screens.OnlinePlay.Match }, }, // Footer - new[] + new Drawable[] { - CreateFooter() + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4Extensions.FromHex(@"28242d") // Temporary. + }, + CreateFooter() + } + } } } } @@ -382,10 +394,19 @@ namespace osu.Game.Screens.OnlinePlay.Match track.Looping = false; } + /// + /// Creates the main centred content. + /// protected abstract Drawable CreateMainContent(); + /// + /// Creates the footer content. + /// protected abstract Drawable CreateFooter(); + /// + /// Creates the room settings overlay. + /// protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(); private class UserModSelectOverlay : LocalPlayerModSelectOverlay diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index d4f5428bfb..9e8d51e64e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -2,18 +2,13 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { public class MultiplayerMatchFooter : CompositeDrawable { - public const float HEIGHT = 50; private const float ready_button_width = 600; private const float spectate_button_width = 200; @@ -27,54 +22,42 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match set => spectateButton.OnSpectateClick = value; } - private readonly Drawable background; private readonly MultiplayerReadyButton readyButton; private readonly MultiplayerSpectateButton spectateButton; public MultiplayerMatchFooter() { - RelativeSizeAxes = Axes.X; - Height = HEIGHT; + RelativeSizeAxes = Axes.Both; - InternalChildren = new[] + InternalChild = new GridContainer { - background = new Box { RelativeSizeAxes = Axes.Both }, - new GridContainer + RelativeSizeAxes = Axes.Both, + Content = new[] { - RelativeSizeAxes = Axes.Both, - Content = new[] + new Drawable[] { - new Drawable[] + null, + spectateButton = new MultiplayerSpectateButton { - null, - spectateButton = new MultiplayerSpectateButton - { - RelativeSizeAxes = Axes.Both, - }, - null, - readyButton = new MultiplayerReadyButton - { - RelativeSizeAxes = Axes.Both, - }, - null - } - }, - ColumnDimensions = new[] - { - new Dimension(), - new Dimension(maxSize: spectate_button_width), - new Dimension(GridSizeMode.Absolute, 10), - new Dimension(maxSize: ready_button_width), - new Dimension() + RelativeSizeAxes = Axes.Both, + }, + null, + readyButton = new MultiplayerReadyButton + { + RelativeSizeAxes = Axes.Both, + }, + null } + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(maxSize: spectate_button_width), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(maxSize: ready_button_width), + new Dimension() } }; } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - background.Colour = Color4Extensions.FromHex(@"28242d"); - } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index f8e5d7d901..3f5837cbbe 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -94,17 +94,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, true); } - protected override void UpdateMods() - { - if (SelectedItem.Value == null || client.LocalUser == null) - return; - - // update local mods based on room's reported status for the local user (omitting the base call implementation). - // this makes the server authoritative, and avoids the local user potentially setting mods that the server is not aware of (ie. if the match was started during the selection being changed). - var ruleset = Ruleset.Value.CreateInstance(); - Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); - } - protected override Drawable CreateMainContent() => new GridContainer { RelativeSizeAxes = Axes.Both, @@ -236,6 +225,17 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new MultiplayerMatchSettingsOverlay(); + protected override void UpdateMods() + { + if (SelectedItem.Value == null || client.LocalUser == null) + return; + + // update local mods based on room's reported status for the local user (omitting the base call implementation). + // this makes the server authoritative, and avoids the local user potentially setting mods that the server is not aware of (ie. if the match was started during the selection being changed). + var ruleset = Ruleset.Value.CreateInstance(); + Mods.Value = client.LocalUser.Mods.Select(m => m.ToMod(ruleset)).Concat(SelectedItem.Value.RequiredMods).ToList(); + } + [Resolved(canBeNull: true)] private DialogOverlay dialogOverlay { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs new file mode 100644 index 0000000000..3eb1cde0a4 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomFooter.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Playlists +{ + public class PlaylistsRoomFooter : CompositeDrawable + { + public Action OnStart; + + public PlaylistsRoomFooter() + { + RelativeSizeAxes = Axes.Both; + + InternalChildren = new[] + { + new PlaylistsReadyButton + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Y, + Size = new Vector2(600, 1), + Action = () => OnStart?.Invoke() + } + }; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 9855d1cb95..27de781d5f 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -20,7 +20,6 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Users; using osuTK; -using Footer = osu.Game.Screens.OnlinePlay.Match.Components.Footer; namespace osu.Game.Screens.OnlinePlay.Playlists { @@ -70,17 +69,6 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, true); } - private void updatePollingRate() - { - selectionPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 30000 : 5000; - Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})"); - } - - protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value) - { - Exited = () => leaderboard.RefreshScores() - }); - protected override Drawable CreateMainContent() => new GridContainer { RelativeSizeAxes = Axes.Both, @@ -190,7 +178,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists } }; - protected override Drawable CreateFooter() => new Footer + protected override Drawable CreateFooter() => new PlaylistsRoomFooter { OnStart = StartPlay }; @@ -203,5 +191,16 @@ namespace osu.Game.Screens.OnlinePlay.Playlists this.Push(new PlaylistsSongSelect()); }, }; + + private void updatePollingRate() + { + selectionPollingComponent.TimeBetweenPolls.Value = isIdle.Value ? 30000 : 5000; + Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})"); + } + + protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value) + { + Exited = () => leaderboard.RefreshScores() + }); } } From eadf02933a735ea97ce8dbd69fb6a35f2318525d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 20:53:17 +0900 Subject: [PATCH 451/961] Split lounge-specific implementation from DrawableRoom --- .../Multiplayer/TestSceneDrawableRoom.cs | 7 +- .../TestSceneLoungeRoomsContainer.cs | 3 +- .../Multiplayer/TestSceneMultiplayer.cs | 4 +- .../TestSceneMultiplayerLoungeSubScreen.cs | 13 +- .../Lounge/Components/DrawableRoom.cs | 263 ++---------------- .../Lounge/Components/RoomsContainer.cs | 22 +- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 225 +++++++++++++++ .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 1 - 8 files changed, 269 insertions(+), 269 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 299bbacf08..489ece3271 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -10,11 +10,11 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Framework.Utils; -using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Online.Rooms.RoomStatuses; using osu.Game.Overlays; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Beatmaps; using osu.Game.Users; @@ -159,10 +159,7 @@ namespace osu.Game.Tests.Visual.Multiplayer })); } - var drawableRoom = new DrawableRoom(room) { MatchingFilter = true }; - drawableRoom.Action = () => drawableRoom.State = drawableRoom.State == SelectionState.Selected ? SelectionState.NotSelected : SelectionState.Selected; - - return drawableRoom; + return new DrawableLoungeRoom(room) { MatchingFilter = true }; } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 7e822f898e..b23638e514 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -9,6 +9,7 @@ using osu.Framework.Testing; using osu.Game.Online.Rooms; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Tests.Visual.OnlinePlay; using osuTK.Input; @@ -150,6 +151,6 @@ namespace osu.Game.Tests.Visual.Multiplayer private bool checkRoomSelected(Room room) => SelectedRoom.Value == room; private Room getRoomInFlow(int index) => - (container.ChildrenOfType>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room; + (container.ChildrenOfType>().First().FlowingChildren.ElementAt(index) as DrawableRoom)?.Room; } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index e618b28f40..6c1aed71e6 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -236,8 +236,8 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("join room", () => InputManager.Key(Key.Enter)); - DrawableRoom.PasswordEntryPopover passwordEntryPopover = null; - AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); + DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null; + AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password"); AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick()); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index c66d5429d6..4ec02a6ec8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -9,7 +9,6 @@ using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge; -using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Tests.Visual.OnlinePlay; using osuTK.Input; @@ -59,20 +58,20 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("attempt join room", () => InputManager.Key(Key.Enter)); - AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType().Any()); + AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType().Any()); AddStep("exit screen", () => Stack.Exit()); - AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType().Any()); + AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType().Any()); } [Test] public void TestJoinRoomWithPassword() { - DrawableRoom.PasswordEntryPopover passwordEntryPopover = null; + DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null; AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true)); AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("attempt join room", () => InputManager.Key(Key.Enter)); - AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); + AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password"); AddStep("press join room button", () => passwordEntryPopover.ChildrenOfType().First().TriggerClick()); @@ -83,12 +82,12 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestJoinRoomWithPasswordViaKeyboardOnly() { - DrawableRoom.PasswordEntryPopover passwordEntryPopover = null; + DrawableLoungeRoom.PasswordEntryPopover passwordEntryPopover = null; AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true)); AddStep("select room", () => InputManager.Key(Key.Down)); AddStep("attempt join room", () => InputManager.Key(Key.Enter)); - AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); + AddUntilStep("password prompt appeared", () => (passwordEntryPopover = InputManager.ChildrenOfType().FirstOrDefault()) != null); AddStep("enter password in text box", () => passwordEntryPopover.ChildrenOfType().First().Text = "password"); AddStep("press enter", () => InputManager.Key(Key.Enter)); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index b627dfbb8e..c5b8bffbc6 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -1,32 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using System.Collections.Generic; -using osu.Framework; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Bindables; -using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input.Bindings; -using osu.Framework.Input.Events; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; -using osu.Game.Graphics.UserInterfaceV2; -using osu.Game.Input.Bindings; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.OnlinePlay.Components; @@ -35,104 +22,17 @@ using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay.Lounge.Components { - public class DrawableRoom : OsuClickableContainer, IStateful, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler + public class DrawableRoom : CompositeDrawable { - public const float SELECTION_BORDER_WIDTH = 4; - private const float corner_radius = 10; - private const float transition_duration = 60; + protected const float CORNER_RADIUS = 10; private const float height = 100; - public event Action StateChanged; - - protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds(); - - private Drawable selectionBox; - - [Resolved(canBeNull: true)] - private LoungeSubScreen loungeScreen { get; set; } + public readonly Room Room; [Resolved] private BeatmapManager beatmaps { get; set; } - [Resolved(canBeNull: true)] - private Bindable selectedRoom { get; set; } - - [Resolved(canBeNull: true)] - private LoungeSubScreen lounge { get; set; } - - public readonly Room Room; - - private SelectionState state; - - private Sample sampleSelect; - private Sample sampleJoin; - - public SelectionState State - { - get => state; - set - { - if (value == state) - return; - - state = value; - - if (selectionBox != null) - { - if (state == SelectionState.Selected) - selectionBox.FadeIn(transition_duration); - else - selectionBox.FadeOut(transition_duration); - } - - StateChanged?.Invoke(State); - } - } - - public IEnumerable FilterTerms => new[] { Room.Name.Value }; - - private bool matchingFilter; - - public bool MatchingFilter - { - get => matchingFilter; - set - { - matchingFilter = value; - - if (!IsLoaded) - return; - - if (matchingFilter) - this.FadeIn(200); - else - Hide(); - } - } - - private int numberOfAvatars = 7; - - public int NumberOfAvatars - { - get => numberOfAvatars; - set - { - numberOfAvatars = value; - - if (recentParticipantsList != null) - recentParticipantsList.NumberOfCircles = value; - } - } - - public bool FilteringActive { get; set; } - - protected readonly Container ButtonsContainer = new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X - }; + protected Container ButtonsContainer { get; private set; } private readonly Bindable roomCategory = new Bindable(); private readonly Bindable hasPassword = new Bindable(); @@ -149,7 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Height = height; Masking = true; - CornerRadius = corner_radius; + CornerRadius = CORNER_RADIUS; EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, @@ -159,9 +59,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colours, AudioManager audio) + private void load(OverlayColourProvider colours) { - Children = new Drawable[] + InternalChildren = new Drawable[] { // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. new Box @@ -183,7 +83,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { RelativeSizeAxes = Axes.Both, Masking = true, - CornerRadius = corner_radius, + CornerRadius = CORNER_RADIUS, Children = new Drawable[] { new GridContainer @@ -303,7 +203,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { - ButtonsContainer, + ButtonsContainer = new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }, recentParticipantsList = new RecentParticipantsList { Anchor = Anchor.CentreRight, @@ -316,36 +222,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, }, }, - new StatusColouredContainer(transition_duration) - { - RelativeSizeAxes = Axes.Both, - Child = selectionBox = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = state == SelectionState.Selected ? 1 : 0, - Masking = true, - CornerRadius = corner_radius, - BorderThickness = SELECTION_BORDER_WIDTH, - BorderColour = Color4.White, - Child = new Box - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - AlwaysPresent = true - } - } - }, - }; - - sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); - sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select"); - } - - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - return new CachedModelDependencyContainer(base.CreateChildDependencies(parent)) - { - Model = { Value = Room } }; } @@ -353,11 +229,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { base.LoadComplete(); - if (matchingFilter) - this.FadeInFromZero(transition_duration); - else - Alpha = 0; - roomCategory.BindTo(Room.Category); roomCategory.BindValueChanged(c => { @@ -371,57 +242,26 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true); } - public Popover GetPopover() => new PasswordEntryPopover(Room) { JoinRequested = lounge.Join }; - - public MenuItem[] ContextMenuItems => new MenuItem[] + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { - new OsuMenuItem("Create copy", MenuItemType.Standard, () => + return new CachedModelDependencyContainer(base.CreateChildDependencies(parent)) { - lounge?.Open(Room.DeepClone()); - }) - }; - - public bool OnPressed(GlobalAction action) - { - if (selectedRoom.Value != Room) - return false; - - switch (action) - { - case GlobalAction.Select: - TriggerClick(); - return true; - } - - return false; + Model = { Value = Room } + }; } - public void OnReleased(GlobalAction action) + private int numberOfAvatars = 7; + + public int NumberOfAvatars { - } - - protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected || child is HoverSounds; - - protected override bool OnClick(ClickEvent e) - { - if (Room != selectedRoom.Value) + get => numberOfAvatars; + set { - sampleSelect?.Play(); - selectedRoom.Value = Room; - return true; + numberOfAvatars = value; + + if (recentParticipantsList != null) + recentParticipantsList.NumberOfCircles = value; } - - if (Room.HasPassword.Value) - { - sampleJoin?.Play(); - this.ShowPopover(); - return true; - } - - sampleJoin?.Play(); - lounge?.Join(Room, null); - - return base.OnClick(e); } private class RoomNameText : OsuSpriteText @@ -508,52 +348,5 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }; } } - - public class PasswordEntryPopover : OsuPopover - { - private readonly Room room; - - public Action JoinRequested; - - public PasswordEntryPopover(Room room) - { - this.room = room; - } - - private OsuPasswordTextBox passwordTextbox; - - [BackgroundDependencyLoader] - private void load() - { - Child = new FillFlowContainer - { - Margin = new MarginPadding(10), - Spacing = new Vector2(5), - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - passwordTextbox = new OsuPasswordTextBox - { - Width = 200, - }, - new TriangleButton - { - Width = 80, - Text = "Join Room", - Action = () => JoinRequested?.Invoke(room, passwordTextbox.Text) - } - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox)); - passwordTextbox.OnCommit += (_, __) => JoinRequested?.Invoke(room, passwordTextbox.Text); - } - } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index e243477a8c..be5558ed0b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -15,7 +15,6 @@ using osu.Framework.Input.Events; using osu.Framework.Threading; using osu.Game.Extensions; using osu.Game.Graphics.Cursor; -using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; using osu.Game.Online.Rooms; using osuTK; @@ -26,7 +25,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { private readonly IBindableList rooms = new BindableList(); - private readonly FillFlowContainer roomFlow; + private readonly FillFlowContainer roomFlow; public IReadOnlyList Rooms => roomFlow.FlowingChildren.Cast().ToArray(); @@ -56,7 +55,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = roomFlow = new FillFlowContainer + Child = roomFlow = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -74,16 +73,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components rooms.BindTo(roomManager.Rooms); Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true); - - selectedRoom.BindValueChanged(selection => - { - updateSelection(); - }, true); } - private void updateSelection() => - roomFlow.Children.ForEach(r => r.State = r.Room == selectedRoom.Value ? SelectionState.Selected : SelectionState.NotSelected); - private void applyFilterCriteria(FilterCriteria criteria) { roomFlow.Children.ForEach(r => @@ -122,22 +113,17 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { foreach (var room in rooms) { - roomFlow.Add(new DrawableRoom(room)); + roomFlow.Add(new DrawableLoungeRoom(room)); } applyFilterCriteria(Filter?.Value); - - updateSelection(); } private void removeRooms(IEnumerable rooms) { foreach (var r in rooms) { - var toRemove = roomFlow.Single(d => d.Room == r); - toRemove.Action = null; - - roomFlow.Remove(toRemove); + roomFlow.RemoveAll(d => d.Room == r); // selection may have a lease due to being in a sub screen. if (!selectedRoom.Disabled) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs new file mode 100644 index 0000000000..764d4e9d3a --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -0,0 +1,225 @@ +// 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.Audio; +using osu.Framework.Audio.Sample; +using osu.Framework.Bindables; +using osu.Framework.Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; +using osu.Game.Graphics.UserInterface; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Input.Bindings; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge.Components; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.OnlinePlay.Lounge +{ + /// + /// A with lounge-specific interactions such as selection and hover sounds. + /// + public class DrawableLoungeRoom : DrawableRoom, IFilterable, IHasContextMenu, IHasPopover, IKeyBindingHandler + { + private const float transition_duration = 60; + private const float selection_border_width = 4; + + [Resolved(canBeNull: true)] + private LoungeSubScreen lounge { get; set; } + + [Resolved(canBeNull: true)] + private Bindable selectedRoom { get; set; } + + private Sample sampleSelect; + private Sample sampleJoin; + private Drawable selectionBox; + + public DrawableLoungeRoom(Room room) + : base(room) + { + } + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); + sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select"); + + AddRangeInternal(new Drawable[] + { + new StatusColouredContainer(transition_duration) + { + RelativeSizeAxes = Axes.Both, + Child = selectionBox = new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = CORNER_RADIUS, + BorderThickness = selection_border_width, + BorderColour = Color4.White, + Child = new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + }, + new HoverSounds() + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + if (matchingFilter) + this.FadeInFromZero(transition_duration); + else + Alpha = 0; + + selectedRoom.BindValueChanged(updateSelectedRoom, true); + } + + private void updateSelectedRoom(ValueChangedEvent selected) + { + if (selected.NewValue == Room) + selectionBox.FadeIn(transition_duration); + else + selectionBox.FadeOut(transition_duration); + } + + public bool FilteringActive { get; set; } + + public IEnumerable FilterTerms => new[] { Room.Name.Value }; + + private bool matchingFilter; + + public bool MatchingFilter + { + get => matchingFilter; + set + { + matchingFilter = value; + + if (!IsLoaded) + return; + + if (matchingFilter) + this.FadeIn(200); + else + Hide(); + } + } + + public Popover GetPopover() => new PasswordEntryPopover(Room) { JoinRequested = lounge.Join }; + + public MenuItem[] ContextMenuItems => new MenuItem[] + { + new OsuMenuItem("Create copy", MenuItemType.Standard, () => + { + lounge?.Open(Room.DeepClone()); + }) + }; + + public bool OnPressed(GlobalAction action) + { + if (selectedRoom.Value != Room) + return false; + + switch (action) + { + case GlobalAction.Select: + TriggerClick(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + } + + protected override bool ShouldBeConsideredForInput(Drawable child) => selectedRoom.Value == Room || child is HoverSounds; + + protected override bool OnClick(ClickEvent e) + { + if (Room != selectedRoom.Value) + { + sampleSelect?.Play(); + selectedRoom.Value = Room; + return true; + } + + if (Room.HasPassword.Value) + { + sampleJoin?.Play(); + this.ShowPopover(); + return true; + } + + sampleJoin?.Play(); + lounge?.Join(Room, null); + + return base.OnClick(e); + } + + public class PasswordEntryPopover : OsuPopover + { + private readonly Room room; + + public Action JoinRequested; + + public PasswordEntryPopover(Room room) + { + this.room = room; + } + + private OsuPasswordTextBox passwordTextbox; + + [BackgroundDependencyLoader] + private void load() + { + Child = new FillFlowContainer + { + Margin = new MarginPadding(10), + Spacing = new Vector2(5), + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + passwordTextbox = new OsuPasswordTextBox + { + Width = 200, + }, + new TriangleButton + { + Width = 80, + Text = "Join Room", + Action = () => JoinRequested?.Invoke(room, passwordTextbox.Text) + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Schedule(() => GetContainingInputManager().ChangeFocus(passwordTextbox)); + passwordTextbox.OnCommit += (_, __) => JoinRequested?.Invoke(room, passwordTextbox.Text); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 42d76e5a15..81fae558c8 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -134,7 +134,6 @@ namespace osu.Game.Screens.OnlinePlay.Match { new DrawableMatchRoom(Room, allowEdit) { - MatchingFilter = true, OnEdit = () => settingsOverlay.Show() } }, From e9221f012635c9e63a7049d8c7a046681b65b0a6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 21:00:11 +0900 Subject: [PATCH 452/961] Cleanup unnecessary implementation --- osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index ead219bee2..b3e6292f45 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -58,7 +58,5 @@ namespace osu.Game.Screens.OnlinePlay.Match if (editButton != null) host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); } - - protected override bool ShouldBeConsideredForInput(Drawable child) => true; } } From d40023bcc1ff1e612a48dd78f60b32e31c8e868e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 18 Aug 2021 21:09:34 +0900 Subject: [PATCH 453/961] Hide border by default --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 764d4e9d3a..4e106b844c 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -63,6 +63,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Child = selectionBox = new Container { RelativeSizeAxes = Axes.Both, + Alpha = 0, Masking = true, CornerRadius = CORNER_RADIUS, BorderThickness = selection_border_width, From af0c7ed108387b4e77ee8bf4f902dafbd2f12551 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 01:25:57 +0900 Subject: [PATCH 454/961] Fix searching in settings not correctly invalidating the scroll position --- osu.Game/Graphics/Containers/SectionsContainer.cs | 11 ++++++++++- osu.Game/Overlays/SettingsPanel.cs | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 8ab146efe7..b3dd44f0e1 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -170,13 +170,22 @@ namespace osu.Game.Graphics.Containers if (source == InvalidationSource.Child && (invalidation & Invalidation.DrawSize) != 0) { - lastKnownScroll = null; + InvalidateScrollPosition(); result = true; } return result; } + protected void InvalidateScrollPosition() + { + Schedule(() => + { + lastKnownScroll = null; + lastClickedSection = null; + }); + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 376e36ea4e..83b0d9c7dc 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -273,6 +273,16 @@ namespace osu.Game.Overlays { public SearchContainer SearchContainer; + public string SearchTerm + { + get => SearchContainer.SearchTerm; + set + { + SearchContainer.SearchTerm = value; + InvalidateScrollPosition(); + } + } + protected override FlowContainer CreateScrollContentContainer() => SearchContainer = new SearchContainer { From a0374d4a67c2274673f05452e9d050451f7d07e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 01:26:11 +0900 Subject: [PATCH 455/961] Adjust centre point slightly to make dim feel better --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index b3dd44f0e1..2dc69b0bd0 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -111,7 +111,7 @@ namespace osu.Game.Graphics.Containers /// /// The percentage of the container to consider the centre-point for deciding the active section (and scrolling to a requested section). /// - private const float scroll_y_centre = 0.1f; + private const float scroll_y_centre = 0.2f; public SectionsContainer() { From e87accafc88cc5ea384b7441893d1a95a3739354 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 01:26:33 +0900 Subject: [PATCH 456/961] Fix current section logic not accounting for hidden sections --- osu.Game/Graphics/Containers/SectionsContainer.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 2dc69b0bd0..e11d1e1300 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -22,6 +22,7 @@ namespace osu.Game.Graphics.Containers where T : Drawable { public Bindable SelectedSection { get; } = new Bindable(); + private Drawable lastClickedSection; public Drawable ExpandableHeader @@ -233,15 +234,17 @@ namespace osu.Game.Graphics.Containers float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection; + var presentChildren = Children.Where(c => c.IsPresent); + if (Precision.AlmostBigger(0, scrollContainer.Current)) - SelectedSection.Value = lastClickedSection as T ?? Children.FirstOrDefault(); + SelectedSection.Value = lastClickedSection as T ?? presentChildren.FirstOrDefault(); else if (Precision.AlmostBigger(scrollContainer.Current, scrollContainer.ScrollableExtent)) - SelectedSection.Value = lastClickedSection as T ?? Children.LastOrDefault(); + SelectedSection.Value = lastClickedSection as T ?? presentChildren.LastOrDefault(); else { - SelectedSection.Value = Children + SelectedSection.Value = presentChildren .TakeWhile(section => scrollContainer.GetChildPosInContent(section) - currentScroll - scrollCentre <= 0) - .LastOrDefault() ?? Children.FirstOrDefault(); + .LastOrDefault() ?? presentChildren.FirstOrDefault(); } } } From 6637c64501aab585fe3e110e3833a1b2eab35fc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 01:27:14 +0900 Subject: [PATCH 457/961] Dim all but the current section --- osu.Game/Overlays/Settings/SettingsSection.cs | 49 ++++++++++++++++++- osu.Game/Overlays/SettingsPanel.cs | 13 +++-- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index f993a46dc6..8d98ae484f 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -4,9 +4,11 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -19,6 +21,10 @@ namespace osu.Game.Overlays.Settings protected FillFlowContainer FlowContent; protected override Container Content => FlowContent; + private IBindable selectedSection; + + private Container content; + public abstract Drawable CreateIcon(); public abstract LocalisableString Header { get; } @@ -36,6 +42,9 @@ namespace osu.Game.Overlays.Settings public bool FilteringActive { get; set; } + [Resolved] + private SettingsPanel settingsPanel { get; set; } + protected SettingsSection() { Margin = new MarginPadding { Top = margin }; @@ -65,7 +74,7 @@ namespace osu.Game.Overlays.Settings RelativeSizeAxes = Axes.X, Height = border_size, }, - new Container + content = new Container { Padding = new MarginPadding { @@ -91,6 +100,44 @@ namespace osu.Game.Overlays.Settings } }, }); + + selectedSection = settingsPanel.CurrentSection.GetBoundCopy(); + selectedSection.BindValueChanged(selected => + { + if (selected.NewValue == this) + content.FadeIn(500, Easing.OutQuint); + else + content.FadeTo(0.25f, 500, Easing.OutQuint); + }, true); + } + + private bool isCurrentSection => selectedSection.Value == this; + + protected override bool OnHover(HoverEvent e) + { + if (!isCurrentSection) + content.FadeTo(0.6f, 500, Easing.OutQuint); + return base.OnHover(e); + } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (!isCurrentSection) + content.FadeTo(0.25f, 500, Easing.OutQuint); + base.OnHoverLost(e); + } + + protected override bool OnClick(ClickEvent e) + { + if (!isCurrentSection) + settingsPanel.SectionsContainer.ScrollTo(this); + + return base.OnClick(e); + } + + protected override bool ShouldBeConsideredForInput(Drawable child) + { + return isCurrentSection; } } } diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 83b0d9c7dc..e4e76592d8 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using osuTK; using osuTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -21,6 +22,7 @@ using osu.Game.Overlays.Settings; namespace osu.Game.Overlays { + [Cached] public abstract class SettingsPanel : OsuFocusedOverlayContainer { public const float CONTENT_MARGINS = 15; @@ -46,7 +48,7 @@ namespace osu.Game.Overlays protected Sidebar Sidebar; private SidebarButton selectedSidebarButton; - protected SettingsSectionsContainer SectionsContainer; + public SettingsSectionsContainer SectionsContainer { get; private set; } private SeekLimitedSearchTextBox searchTextBox; @@ -65,6 +67,8 @@ namespace osu.Game.Overlays private Task sectionsLoadingTask; + public IBindable CurrentSection = new Bindable(); + protected SettingsPanel(bool showSidebar) { this.showSidebar = showSidebar; @@ -105,6 +109,7 @@ namespace osu.Game.Overlays Masking = true, RelativeSizeAxes = Axes.Both, ExpandableHeader = CreateHeader(), + SelectedSection = { BindTarget = CurrentSection }, FixedHeader = searchTextBox = new SeekLimitedSearchTextBox { RelativeSizeAxes = Axes.X, @@ -238,8 +243,10 @@ namespace osu.Game.Overlays if (selectedSidebarButton != null) selectedSidebarButton.Selected = false; - selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); - selectedSidebarButton.Selected = true; + selectedSidebarButton = Sidebar.Children.FirstOrDefault(b => b.Section == section.NewValue); + + if (selectedSidebarButton != null) + selectedSidebarButton.Selected = true; }, true); }); } From 61675eefe0a5fecb4f01661ad717e49b1d398a87 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Wed, 18 Aug 2021 17:36:57 +0100 Subject: [PATCH 458/961] Add length limit to match settings textboxes --- .../Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 61bb39d0c5..7bad661cf4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -48,6 +48,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { BackgroundUnfocused = Color4.Black; BackgroundFocused = Color4.Black; + LengthLimit = 100; } } @@ -63,6 +64,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { BackgroundUnfocused = Color4.Black; BackgroundFocused = Color4.Black; + LengthLimit = 255; } } From ea08d48d273cb2253ed1ddba751d24a3cf369e19 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 18 Aug 2021 18:53:01 +0200 Subject: [PATCH 459/961] Remove unecessary localised string due to online view container handling visibility when user is not logged in. --- osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index 441ef2f6cf..c0460a4536 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private readonly bool noVideo; - public LocalisableString TooltipText => button.Enabled.Value ? BeatmapsetsStrings.ShowDetailsDownloadDefault : BeatmapsetsStrings.ShowDetailsLoggedOut; + public LocalisableString TooltipText => BeatmapsetsStrings.ShowDetailsDownloadDefault; private readonly IBindable localUser = new Bindable(); From 43cbd10a38a8c148ba03a62caf46bcf9c9b73758 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Wed, 18 Aug 2021 18:30:50 +0100 Subject: [PATCH 460/961] change limit to be on actual usage site --- .../Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs | 2 -- .../Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs index 7bad661cf4..61bb39d0c5 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchSettingsOverlay.cs @@ -48,7 +48,6 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { BackgroundUnfocused = Color4.Black; BackgroundFocused = Color4.Black; - LengthLimit = 100; } } @@ -64,7 +63,6 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { BackgroundUnfocused = Color4.Black; BackgroundFocused = Color4.Black; - LengthLimit = 255; } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 338d2c9e84..53d494106b 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -136,6 +136,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { RelativeSizeAxes = Axes.X, TabbableContentContainer = this, + LengthLimit = 100, }, }, new Section("Room visibility") @@ -195,6 +196,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { RelativeSizeAxes = Axes.X, TabbableContentContainer = this, + LengthLimit = 255, }, }, } From ffbe8ddfa4ed5a97c02e9c296479549482224714 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 04:23:02 +0300 Subject: [PATCH 461/961] Refactor lounge sub screen layout for better loading screen appearance --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 117 ++++++++---------- 1 file changed, 51 insertions(+), 66 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 24aad8c124..ee9331b71a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -76,6 +76,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge [BackgroundDependencyLoader(true)] private void load([CanBeNull] IdleTracker idleTracker) { + const float controls_area_height = 25f; + if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); @@ -84,86 +86,69 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter), - new Container + scrollContainer = new OsuScrollContainer { + Name = @"Scrollable rooms container", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { - Left = WaveOverlayContainer.WIDTH_PADDING, - Right = WaveOverlayContainer.WIDTH_PADDING, + Horizontal = WaveOverlayContainer.WIDTH_PADDING, + Top = Header.HEIGHT + controls_area_height + 20, }, - Child = new GridContainer + ScrollbarOverlapsContent = false, + Child = roomsContainer = new RoomsContainer { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + Filter = { BindTarget = filter } + } + }, + loadingLayer = new LoadingLayer(true), + new FillFlowContainer + { + Name = @"Header area flow", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING }, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new Container { - new Dimension(GridSizeMode.Absolute, Header.HEIGHT), - new Dimension(GridSizeMode.Absolute, 25), - new Dimension(GridSizeMode.Absolute, 20) + RelativeSizeAxes = Axes.X, + Height = Header.HEIGHT, + Child = searchTextBox = new LoungeSearchTextBox + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.X, + Width = 0.6f, + }, }, - Content = new[] + new Container { - new Drawable[] + RelativeSizeAxes = Axes.X, + Height = controls_area_height, + Children = new Drawable[] { - searchTextBox = new LoungeSearchTextBox + Buttons.WithChild(CreateNewRoomButton().With(d => { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.X, - Width = 0.6f, - }, - }, - new Drawable[] - { - new Container + d.Anchor = Anchor.BottomLeft; + d.Origin = Anchor.BottomLeft; + d.Size = new Vector2(150, 37.5f); + d.Action = () => Open(); + })), + new FillFlowContainer { - RelativeSizeAxes = Axes.Both, - Depth = float.MinValue, // Contained filters should appear over the top of rooms. - Children = new Drawable[] + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10), + ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d => { - Buttons.WithChild(CreateNewRoomButton().With(d => - { - d.Anchor = Anchor.BottomLeft; - d.Origin = Anchor.BottomLeft; - d.Size = new Vector2(150, 37.5f); - d.Action = () => Open(); - })), - new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10), - ChildrenEnumerable = CreateFilterControls().Select(f => f.With(d => - { - d.Anchor = Anchor.TopRight; - d.Origin = Anchor.TopRight; - })) - } - } + d.Anchor = Anchor.TopRight; + d.Origin = Anchor.TopRight; + })) } - }, - null, - new Drawable[] - { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - scrollContainer = new OsuScrollContainer - { - RelativeSizeAxes = Axes.Both, - ScrollbarOverlapsContent = false, - Child = roomsContainer = new RoomsContainer - { - Filter = { BindTarget = filter } - } - }, - loadingLayer = new LoadingLayer(true), - } - }, } } }, From 0e2f3dff4dda07cd8b388d952f92172a657e9f83 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 05:09:49 +0300 Subject: [PATCH 462/961] Fix rooms scroll container not masking properly due to padding --- .../Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index ee9331b71a..0664e44a73 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -86,20 +86,24 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter), - scrollContainer = new OsuScrollContainer + new Container { - Name = @"Scrollable rooms container", + Name = @"Rooms area", RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Horizontal = WaveOverlayContainer.WIDTH_PADDING, Top = Header.HEIGHT + controls_area_height + 20, }, - ScrollbarOverlapsContent = false, - Child = roomsContainer = new RoomsContainer + Child = scrollContainer = new OsuScrollContainer { - Filter = { BindTarget = filter } - } + RelativeSizeAxes = Axes.Both, + ScrollbarOverlapsContent = false, + Child = roomsContainer = new RoomsContainer + { + Filter = { BindTarget = filter } + } + }, }, loadingLayer = new LoadingLayer(true), new FillFlowContainer From f4ae587a3385c63f90295c02fb118c9af55935eb Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 06:24:06 +0300 Subject: [PATCH 463/961] Extract room request handling logic to its own class --- ...stRequestHandlingMultiplayerRoomManager.cs | 138 ++-------------- .../OnlinePlay/TestRoomRequestsHandler.cs | 147 ++++++++++++++++++ 2 files changed, 159 insertions(+), 126 deletions(-) create mode 100644 osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs diff --git a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs index c3a944f93c..5de518990a 100644 --- a/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs +++ b/osu.Game/Tests/Visual/Multiplayer/TestRequestHandlingMultiplayerRoomManager.cs @@ -1,150 +1,36 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; -using System.Linq; using osu.Framework.Allocation; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Online.Rooms; -using osu.Game.Rulesets.Scoring; -using osu.Game.Scoring; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Tests.Visual.OnlinePlay; namespace osu.Game.Tests.Visual.Multiplayer { /// - /// A for use in multiplayer test scenes. Should generally not be used by itself outside of a . + /// A for use in multiplayer test scenes, backed by a . + /// Should generally not be used by itself outside of a . /// - /// - /// This implementation will pretend to be a server, handling room retrieval and manipulation requests - /// and returning a roughly expected state, without the need for a server to be running. - /// public class TestRequestHandlingMultiplayerRoomManager : MultiplayerRoomManager { - [Resolved] - private IAPIProvider api { get; set; } + public IReadOnlyList ServerSideRooms => handler.ServerSideRooms; - [Resolved] - private OsuGameBase game { get; set; } - - public IReadOnlyList ServerSideRooms => serverSideRooms; - private readonly List serverSideRooms = new List(); - - private int currentRoomId; - private int currentPlaylistItemId; + private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler(); [BackgroundDependencyLoader] - private void load() + private void load(IAPIProvider api, OsuGameBase game) { - int currentScoreId = 0; - - // Handling here is pretending to be a server, while also updating the local state to match - // how the server would eventually respond and update the RoomManager. - ((DummyAPIAccess)api).HandleRequest = req => - { - switch (req) - { - case CreateRoomRequest createRoomRequest: - var apiRoom = new Room(); - - apiRoom.CopyFrom(createRoomRequest.Room); - - // Passwords are explicitly not copied between rooms. - apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value); - apiRoom.Password.Value = createRoomRequest.Room.Password.Value; - - AddServerSideRoom(apiRoom); - - var responseRoom = new APICreatedRoom(); - responseRoom.CopyFrom(createResponseRoom(apiRoom, false)); - - createRoomRequest.TriggerSuccess(responseRoom); - return true; - - case JoinRoomRequest joinRoomRequest: - { - var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value); - - if (joinRoomRequest.Password != room.Password.Value) - { - joinRoomRequest.TriggerFailure(new InvalidOperationException("Invalid password.")); - return true; - } - - joinRoomRequest.TriggerSuccess(); - return true; - } - - case PartRoomRequest partRoomRequest: - partRoomRequest.TriggerSuccess(); - return true; - - case GetRoomsRequest getRoomsRequest: - var roomsWithoutParticipants = new List(); - - foreach (var r in ServerSideRooms) - roomsWithoutParticipants.Add(createResponseRoom(r, false)); - - getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); - return true; - - case GetRoomRequest getRoomRequest: - getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true)); - return true; - - case GetBeatmapSetRequest getBeatmapSetRequest: - var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type); - onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res); - onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e); - - // Get the online API from the game's dependencies. - game.Dependencies.Get().Queue(onlineReq); - return true; - - case CreateRoomScoreRequest createRoomScoreRequest: - createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); - return true; - - case SubmitRoomScoreRequest submitRoomScoreRequest: - submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore - { - ID = currentScoreId++, - Accuracy = 1, - EndedAt = DateTimeOffset.Now, - Passed = true, - Rank = ScoreRank.S, - MaxCombo = 1000, - TotalScore = 1000000, - User = api.LocalUser.Value, - Statistics = new Dictionary() - }); - return true; - } - - return false; - }; + ((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game); } - public void AddServerSideRoom(Room room) - { - room.RoomID.Value ??= currentRoomId++; - for (int i = 0; i < room.Playlist.Count; i++) - room.Playlist[i].ID = currentPlaylistItemId++; - - serverSideRooms.Add(room); - } - - private Room createResponseRoom(Room room, bool withParticipants) - { - var responseRoom = new Room(); - responseRoom.CopyFrom(room); - responseRoom.Password.Value = null; - if (!withParticipants) - responseRoom.RecentParticipants.Clear(); - return responseRoom; - } + /// + /// Adds a room to a local "server-side" list that's returned when a is fired. + /// + /// The room. + public void AddServerSideRoom(Room room) => handler.AddServerSideRoom(room); } } diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs new file mode 100644 index 0000000000..7f975c9985 --- /dev/null +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs @@ -0,0 +1,147 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.OnlinePlay +{ + /// + /// Represents a handler which pretends to be a server, handling room retrieval and manipulation requests + /// and returning a roughly expected state, without the need for a server to be running. + /// + public class TestRoomRequestsHandler + { + public IReadOnlyList ServerSideRooms => serverSideRooms; + + private readonly List serverSideRooms = new List(); + + private int currentRoomId; + private int currentPlaylistItemId; + private int currentScoreId; + + /// + /// Handles an API request, while also updating the local state to match + /// how the server would eventually respond and update an . + /// + /// The API request to handle. + /// The local user to store in responses where required. + /// The game base for cases where actual online requests need to be sent. + /// Whether the request was successfully handled. + public bool HandleRequest(APIRequest request, User localUser, OsuGameBase game) + { + switch (request) + { + case CreateRoomRequest createRoomRequest: + var apiRoom = new Room(); + + apiRoom.CopyFrom(createRoomRequest.Room); + + // Passwords are explicitly not copied between rooms. + apiRoom.HasPassword.Value = !string.IsNullOrEmpty(createRoomRequest.Room.Password.Value); + apiRoom.Password.Value = createRoomRequest.Room.Password.Value; + + AddServerSideRoom(apiRoom); + + var responseRoom = new APICreatedRoom(); + responseRoom.CopyFrom(createResponseRoom(apiRoom, false)); + + createRoomRequest.TriggerSuccess(responseRoom); + return true; + + case JoinRoomRequest joinRoomRequest: + { + var room = ServerSideRooms.Single(r => r.RoomID.Value == joinRoomRequest.Room.RoomID.Value); + + if (joinRoomRequest.Password != room.Password.Value) + { + joinRoomRequest.TriggerFailure(new InvalidOperationException("Invalid password.")); + return true; + } + + joinRoomRequest.TriggerSuccess(); + return true; + } + + case PartRoomRequest partRoomRequest: + partRoomRequest.TriggerSuccess(); + return true; + + case GetRoomsRequest getRoomsRequest: + var roomsWithoutParticipants = new List(); + + foreach (var r in ServerSideRooms) + roomsWithoutParticipants.Add(createResponseRoom(r, false)); + + getRoomsRequest.TriggerSuccess(roomsWithoutParticipants); + return true; + + case GetRoomRequest getRoomRequest: + getRoomRequest.TriggerSuccess(createResponseRoom(ServerSideRooms.Single(r => r.RoomID.Value == getRoomRequest.RoomId), true)); + return true; + + case GetBeatmapSetRequest getBeatmapSetRequest: + var onlineReq = new GetBeatmapSetRequest(getBeatmapSetRequest.ID, getBeatmapSetRequest.Type); + onlineReq.Success += res => getBeatmapSetRequest.TriggerSuccess(res); + onlineReq.Failure += e => getBeatmapSetRequest.TriggerFailure(e); + + // Get the online API from the game's dependencies. + game.Dependencies.Get().Queue(onlineReq); + return true; + + case CreateRoomScoreRequest createRoomScoreRequest: + createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); + return true; + + case SubmitRoomScoreRequest submitRoomScoreRequest: + submitRoomScoreRequest.TriggerSuccess(new MultiplayerScore + { + ID = currentScoreId++, + Accuracy = 1, + EndedAt = DateTimeOffset.Now, + Passed = true, + Rank = ScoreRank.S, + MaxCombo = 1000, + TotalScore = 1000000, + User = localUser, + Statistics = new Dictionary() + }); + return true; + } + + return false; + } + + /// + /// Adds a room to a local "server-side" list that's returned when a is fired. + /// + /// The room. + public void AddServerSideRoom(Room room) + { + room.RoomID.Value ??= currentRoomId++; + for (int i = 0; i < room.Playlist.Count; i++) + room.Playlist[i].ID = currentPlaylistItemId++; + + serverSideRooms.Add(room); + } + + private Room createResponseRoom(Room room, bool withParticipants) + { + var responseRoom = new Room(); + responseRoom.CopyFrom(room); + responseRoom.Password.Value = null; + if (!withParticipants) + responseRoom.RecentParticipants.Clear(); + return responseRoom; + } + } +} From 49bc3a8250aeb0d5875f0461ef07eada7c82d915 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 06:25:47 +0300 Subject: [PATCH 464/961] Refactor playlists room manager to handle dummy API requests --- .../TestSceneLoungeRoomsContainer.cs | 4 +- .../TestSceneMultiplayerLoungeSubScreen.cs | 2 +- .../TestScenePlaylistsLoungeSubScreen.cs | 2 +- .../TestScenePlaylistsRoomSubScreen.cs | 13 -- .../Visual/OnlinePlay/BasicTestRoomManager.cs | 111 ------------------ .../OnlinePlayTestSceneDependencies.cs | 2 +- .../TestRequestHandlingRoomManager.cs | 76 ++++++++++++ 7 files changed, 81 insertions(+), 129 deletions(-) delete mode 100644 osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs create mode 100644 osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index 7e822f898e..d253b7f8cf 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneLoungeRoomsContainer : OnlinePlayTestScene { - protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager; + protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager; private RoomsContainer container; @@ -38,7 +38,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("add rooms", () => RoomManager.AddRooms(3)); AddAssert("has 3 rooms", () => container.Rooms.Count == 3); - AddStep("remove first room", () => RoomManager.Rooms.Remove(RoomManager.Rooms.FirstOrDefault())); + AddStep("remove first room", () => RoomManager.RemoveRoom(RoomManager.Rooms.FirstOrDefault())); AddAssert("has 2 rooms", () => container.Rooms.Count == 2); AddAssert("first room removed", () => container.Rooms.All(r => r.Room.RoomID.Value != 0)); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index c66d5429d6..cc05bc24aa 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -18,7 +18,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneMultiplayerLoungeSubScreen : OnlinePlayTestScene { - protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager; + protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager; private LoungeSubScreen loungeScreen; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index aff0e7ba4b..f432a6436e 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Playlists { public class TestScenePlaylistsLoungeSubScreen : OnlinePlayTestScene { - protected new BasicTestRoomManager RoomManager => (BasicTestRoomManager)base.RoomManager; + protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager; private LoungeSubScreen loungeScreen; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 9fc29049ef..28090be1f6 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -11,7 +11,6 @@ using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Beatmaps; -using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; @@ -36,18 +35,6 @@ namespace osu.Game.Tests.Visual.Playlists { Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); - - ((DummyAPIAccess)API).HandleRequest = req => - { - switch (req) - { - case CreateRoomScoreRequest createRoomScoreRequest: - createRoomScoreRequest.TriggerSuccess(new APIScoreToken { ID = 1 }); - return true; - } - - return false; - }; } [SetUpSteps] diff --git a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs deleted file mode 100644 index 55fbb9f1a6..0000000000 --- a/osu.Game/Tests/Visual/OnlinePlay/BasicTestRoomManager.cs +++ /dev/null @@ -1,111 +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.Bindables; -using osu.Game.Beatmaps; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Screens.OnlinePlay; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Users; - -namespace osu.Game.Tests.Visual.OnlinePlay -{ - /// - /// A very simple for use in online play test scenes. - /// - public class BasicTestRoomManager : IRoomManager - { - public event Action RoomsUpdated; - - public readonly BindableList Rooms = new BindableList(); - - public Action JoinRoomRequested; - - public IBindable InitialRoomsReceived { get; } = new Bindable(true); - - IBindableList IRoomManager.Rooms => Rooms; - - private int currentRoomId; - - public void CreateRoom(Room room, Action onSuccess = null, Action onError = null) - { - room.RoomID.Value ??= Rooms.Select(r => r.RoomID.Value).Where(id => id != null).Select(id => id.Value).DefaultIfEmpty().Max() + 1; - onSuccess?.Invoke(room); - - AddOrUpdateRoom(room); - } - - public void AddOrUpdateRoom(Room room) - { - var existing = Rooms.FirstOrDefault(r => r.RoomID.Value != null && r.RoomID.Value == room.RoomID.Value); - - if (existing != null) - existing.CopyFrom(room); - else - Rooms.Add(room); - - RoomsUpdated?.Invoke(); - } - - public void RemoveRoom(Room room) - { - Rooms.Remove(room); - RoomsUpdated?.Invoke(); - } - - public void ClearRooms() - { - Rooms.Clear(); - RoomsUpdated?.Invoke(); - } - - public void JoinRoom(Room room, string password, Action onSuccess = null, Action onError = null) - { - JoinRoomRequested?.Invoke(room, password); - onSuccess?.Invoke(room); - } - - public void PartRoom() - { - } - - public void AddRooms(int count, RulesetInfo ruleset = null, bool withPassword = false) - { - for (int i = 0; i < count; i++) - { - var room = new Room - { - RoomID = { Value = currentRoomId }, - Position = { Value = currentRoomId }, - Name = { Value = $"Room {currentRoomId}" }, - Host = { Value = new User { Username = "Host" } }, - EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }, - Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal }, - Password = { Value = withPassword ? "password" : string.Empty } - }; - - if (ruleset != null) - { - room.Playlist.Add(new PlaylistItem - { - Ruleset = { Value = ruleset }, - Beatmap = - { - Value = new BeatmapInfo - { - Metadata = new BeatmapMetadata() - } - } - }); - } - - CreateRoom(room); - - currentRoomId++; - } - } - } -} diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs index e39711b7ce..defc971eef 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestSceneDependencies.cs @@ -71,6 +71,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay drawableComponents.Add(drawable); } - protected virtual IRoomManager CreateRoomManager() => new BasicTestRoomManager(); + protected virtual IRoomManager CreateRoomManager() => new TestRequestHandlingRoomManager(); } } diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs new file mode 100644 index 0000000000..4c7fc0e18f --- /dev/null +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs @@ -0,0 +1,76 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Game.Beatmaps; +using osu.Game.Online.API; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.OnlinePlay +{ + /// + /// A very simple for use in online play test scenes. + /// + public class TestRequestHandlingRoomManager : RoomManager + { + public Action JoinRoomRequested; + + private int currentRoomId; + + private readonly TestRoomRequestsHandler handler = new TestRoomRequestsHandler(); + + [BackgroundDependencyLoader] + private void load(IAPIProvider api, OsuGameBase game) + { + ((DummyAPIAccess)api).HandleRequest = request => handler.HandleRequest(request, api.LocalUser.Value, game); + } + + public override void JoinRoom(Room room, string password = null, Action onSuccess = null, Action onError = null) + { + JoinRoomRequested?.Invoke(room, password); + base.JoinRoom(room, password, onSuccess, onError); + } + + public void AddRooms(int count, RulesetInfo ruleset = null, bool withPassword = false) + { + for (int i = 0; i < count; i++) + { + var room = new Room + { + RoomID = { Value = -currentRoomId }, + Name = { Value = $@"Room {currentRoomId}" }, + Host = { Value = new User { Username = @"Host" } }, + EndDate = { Value = DateTimeOffset.Now + TimeSpan.FromSeconds(10) }, + Category = { Value = i % 2 == 0 ? RoomCategory.Spotlight : RoomCategory.Normal }, + }; + + if (withPassword) + room.Password.Value = @"password"; + + if (ruleset != null) + { + room.Playlist.Add(new PlaylistItem + { + Ruleset = { Value = ruleset }, + Beatmap = + { + Value = new BeatmapInfo + { + Metadata = new BeatmapMetadata() + } + } + }); + } + + CreateRoom(room); + + currentRoomId++; + } + } + } +} From 47ef33e7316bc93b7f001da29a3d9f8196e685d7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 06:28:31 +0300 Subject: [PATCH 465/961] Fix playlists lounge sub screen test potentially failing --- .../Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index aff0e7ba4b..509b62f69f 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -37,6 +37,7 @@ namespace osu.Game.Tests.Visual.Playlists AddStep("reset mouse", () => InputManager.ReleaseButton(MouseButton.Left)); AddStep("add rooms", () => RoomManager.AddRooms(30)); + AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30); AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0])); @@ -53,6 +54,7 @@ namespace osu.Game.Tests.Visual.Playlists public void TestScrollSelectedIntoView() { AddStep("add rooms", () => RoomManager.AddRooms(30)); + AddUntilStep("wait for rooms", () => roomsContainer.Rooms.Count == 30); AddUntilStep("first room is not masked", () => checkRoomVisible(roomsContainer.Rooms[0])); From 5fc29328cf1411bea9bc4f4c093ec32b6849087d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 06:30:22 +0300 Subject: [PATCH 466/961] Remove unused using Uh..... --- .../Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs index 4c7fc0e18f..d88fd68b20 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/TestRequestHandlingRoomManager.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.Game.Beatmaps; using osu.Game.Online.API; From 072560ba3e583d5660f3df7d76999bca1264e390 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 07:17:42 +0300 Subject: [PATCH 467/961] Remove leftover unused using --- osu.Game/Rulesets/Mods/Mod.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 8c2a8a8e8b..9f3b5eaf5b 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using JetBrains.Annotations; using Newtonsoft.Json; using osu.Framework.Bindables; using osu.Framework.Extensions.TypeExtensions; From 6d57a240acf5cd9528b2f688e4a5e4c0388eaaf6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 07:17:22 +0300 Subject: [PATCH 468/961] Add animation support for the star rating display --- .../Beatmaps/Drawables/StarRatingDisplay.cs | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index 25cde5fb82..c239fda455 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; @@ -22,6 +23,7 @@ namespace osu.Game.Beatmaps.Drawables /// public class StarRatingDisplay : CompositeDrawable, IHasCurrentValue { + private readonly bool animated; private readonly Box background; private readonly SpriteIcon starIcon; private readonly OsuSpriteText starsText; @@ -34,6 +36,14 @@ namespace osu.Game.Beatmaps.Drawables set => current.Current = value; } + private readonly Bindable displayedStars = new BindableDouble(); + + /// + /// The currently displayed stars of this display wrapped in a bindable. + /// This bindable gets transformed on change rather than instantaneous, if animation is enabled. + /// + public IBindable DisplayedStars => displayedStars; + [Resolved] private OsuColour colours { get; set; } @@ -45,8 +55,11 @@ namespace osu.Game.Beatmaps.Drawables /// /// The already computed to display. /// The size of the star rating display. - public StarRatingDisplay(StarDifficulty starDifficulty, StarRatingDisplaySize size = StarRatingDisplaySize.Regular) + /// Whether the star rating display will perform transforms on change rather than updating instantaneously. + public StarRatingDisplay(StarDifficulty starDifficulty, StarRatingDisplaySize size = StarRatingDisplaySize.Regular, bool animated = false) { + this.animated = animated; + Current.Value = starDifficulty; AutoSizeAxes = Axes.Both; @@ -112,7 +125,7 @@ namespace osu.Game.Beatmaps.Drawables // see https://github.com/ppy/osu-framework/issues/3271. Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold), Shadow = false, - } + }, } } }, @@ -126,12 +139,22 @@ namespace osu.Game.Beatmaps.Drawables Current.BindValueChanged(c => { - starsText.Text = c.NewValue.Stars.ToString("0.00"); + if (animated) + this.TransformBindableTo(displayedStars, c.NewValue.Stars, 750, Easing.OutQuint); + else + displayedStars.Value = c.NewValue.Stars; + }); - background.Colour = colours.ForStarDifficulty(c.NewValue.Stars); + displayedStars.Value = Current.Value.Stars; - starIcon.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); - starsText.Colour = c.NewValue.Stars >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); + displayedStars.BindValueChanged(s => + { + starsText.Text = s.NewValue.ToLocalisableString("0.00"); + + background.Colour = colours.ForStarDifficulty(s.NewValue); + + starIcon.Colour = s.NewValue >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4Extensions.FromHex("303d47"); + starsText.Colour = s.NewValue >= 6.5 ? colours.Orange1 : colourProvider?.Background5 ?? Color4.Black.Opacity(0.75f); }, true); } } From 25e6317e7f1a51dc6cd15edbafaccb10d499a4d1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 07:18:02 +0300 Subject: [PATCH 469/961] Use animated star display in beatmap info wedge and synchronise bar --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 83 +++++++-------------- 1 file changed, 26 insertions(+), 57 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 14c32f2348..1e1f362d71 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -21,7 +21,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; using osu.Framework.Logging; using osu.Game.Configuration; @@ -157,7 +156,7 @@ namespace osu.Game.Screens.Select public BeatmapSetOnlineStatusPill StatusPill { get; private set; } public FillFlowContainer MapperContainer { get; private set; } - private DifficultyColourBar difficultyColourBar; + private Container difficultyColourBar; private StarRatingDisplay starRatingDisplay; private ILocalisedBindableString titleBinding; @@ -182,7 +181,7 @@ namespace osu.Game.Screens.Select private IBindable starDifficulty; [BackgroundDependencyLoader] - private void load(LocalisationManager localisation, BeatmapDifficultyCache difficultyCache) + private void load(OsuColour colours, LocalisationManager localisation, BeatmapDifficultyCache difficultyCache) { var beatmapInfo = beatmap.BeatmapInfo; var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata(); @@ -194,10 +193,26 @@ namespace osu.Game.Screens.Select Children = new Drawable[] { - difficultyColourBar = new DifficultyColourBar + difficultyColourBar = new Container { RelativeSizeAxes = Axes.Y, - Width = 20, + Width = 20f, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Width = 0.7f, + }, + new Box + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Both, + Alpha = 0.5f, + X = 0.7f, + Width = 1 - 0.7f, + } + } }, new FillFlowContainer { @@ -230,7 +245,7 @@ namespace osu.Game.Screens.Select Shear = wedged_container_shear, Children = new Drawable[] { - starRatingDisplay = new StarRatingDisplay(default) + starRatingDisplay = new StarRatingDisplay(default, animated: true) { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, @@ -292,11 +307,14 @@ namespace osu.Game.Screens.Select titleBinding.BindValueChanged(_ => setMetadata(metadata.Source)); artistBinding.BindValueChanged(_ => setMetadata(metadata.Source), true); + starRatingDisplay.DisplayedStars.BindValueChanged(s => + { + difficultyColourBar.Colour = colours.ForStarDifficulty(s.NewValue); + }, true); + starDifficulty = difficultyCache.GetBindableDifficulty(beatmapInfo, (cancellationSource = new CancellationTokenSource()).Token); starDifficulty.BindValueChanged(s => { - difficultyColourBar.Current.Value = s.NewValue ?? default; - starRatingDisplay.FadeIn(transition_duration); starRatingDisplay.Current.Value = s.NewValue ?? default; }); @@ -480,55 +498,6 @@ namespace osu.Game.Screens.Select }; } } - - public class DifficultyColourBar : Container, IHasCurrentValue - { - private readonly BindableWithCurrent current = new BindableWithCurrent(); - - public Bindable Current - { - get => current.Current; - set => current.Current = value; - } - - [Resolved] - private OsuColour colours { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - const float full_opacity_ratio = 0.7f; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Width = full_opacity_ratio, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Both, - Alpha = 0.5f, - X = full_opacity_ratio, - Width = 1 - full_opacity_ratio, - } - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - Current.BindValueChanged(c => - { - this.FadeColour(colours.ForStarDifficulty(c.NewValue.Stars), transition_duration, Easing.OutQuint); - }, true); - - FinishTransforms(true); - } - } } } } From 65c0ae757bfeb80bf3fe324d80a9cb19dc6d0fcc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 07:18:18 +0300 Subject: [PATCH 470/961] Merge spectrum test case --- .../TestSceneStarRatingDisplay.cs | 28 +------------------ 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs index 052251d5a8..2806e6d347 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneStarRatingDisplay.cs @@ -3,7 +3,6 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Utils; @@ -50,32 +49,7 @@ namespace osu.Game.Tests.Visual.UserInterface { StarRatingDisplay starRating = null; - BindableDouble starRatingNumeric; - - AddStep("load display", () => - { - Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1)) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Scale = new Vector2(3f), - }; - }); - - AddStep("transform over spectrum", () => - { - starRatingNumeric = new BindableDouble(); - starRatingNumeric.BindValueChanged(val => starRating.Current.Value = new StarDifficulty(val.NewValue, 1)); - this.TransformBindableTo(starRatingNumeric, 10, 10000, Easing.OutQuint); - }); - } - - [Test] - public void TestChangingStarRatingDisplay() - { - StarRatingDisplay starRating = null; - - AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1)) + AddStep("load display", () => Child = starRating = new StarRatingDisplay(new StarDifficulty(5.55, 1), animated: true) { Anchor = Anchor.Centre, Origin = Anchor.Centre, From 786beb975941b61a98e1e282f1ad0b16a34a3943 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 14:14:47 +0900 Subject: [PATCH 471/961] Fix missing initial state test step --- .../Visual/Multiplayer/TestSceneGameplayChatDisplay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index 51960680d6..08aa967c61 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -85,6 +85,8 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestFocusOnTabKeyWhenExpanded() { + setLocalUserPlaying(true); + assertChatFocused(false); AddStep("press tab", () => InputManager.Key(Key.Tab)); assertChatFocused(true); From 6d00ea3375d80c953b8978a0b9505226c4506647 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 14:19:59 +0900 Subject: [PATCH 472/961] Allow toggling focus via binding --- .../Multiplayer/TestSceneGameplayChatDisplay.cs | 15 +++++++++++++++ .../Graphics/UserInterface/FocusedTextBox.cs | 2 ++ osu.Game/Input/Bindings/GlobalActionContainer.cs | 6 +++--- .../Multiplayer/GameplayChatDisplay.cs | 16 ++++++++++++---- 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index 08aa967c61..eadfc9b279 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -107,6 +107,21 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("is not visible", () => !chatDisplay.IsPresent); } + [Test] + public void TestFocusToggleViaAction() + { + AddStep("set not expanded", () => chatDisplay.Expanded.Value = false); + AddUntilStep("is not visible", () => !chatDisplay.IsPresent); + + AddStep("press tab", () => InputManager.Key(Key.Tab)); + assertChatFocused(true); + AddUntilStep("is visible", () => chatDisplay.IsPresent); + + AddStep("press tab", () => InputManager.Key(Key.Tab)); + assertChatFocused(false); + AddUntilStep("is not visible", () => !chatDisplay.IsPresent); + } + private void assertChatFocused(bool isFocused) => AddAssert($"chat {(isFocused ? "focused" : "not focused")}", () => textBox.HasFocus == isFocused); diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index f77a3109c9..2705caccff 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -25,6 +25,8 @@ namespace osu.Game.Graphics.UserInterface if (allowImmediateFocus) GetContainingInputManager().ChangeFocus(this); } + public new void KillFocus() => base.KillFocus(); + public bool HoldFocus { get => allowImmediateFocus && focus; diff --git a/osu.Game/Input/Bindings/GlobalActionContainer.cs b/osu.Game/Input/Bindings/GlobalActionContainer.cs index 66edb25d64..0176a00e9d 100644 --- a/osu.Game/Input/Bindings/GlobalActionContainer.cs +++ b/osu.Game/Input/Bindings/GlobalActionContainer.cs @@ -90,7 +90,7 @@ namespace osu.Game.Input.Bindings new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward), new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward), new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD), - new KeyBinding(InputKey.Tab, GlobalAction.FocusChatInput), + new KeyBinding(InputKey.Tab, GlobalAction.ToggleChatFocus), }; public IEnumerable SongSelectKeyBindings => new[] @@ -282,7 +282,7 @@ namespace osu.Game.Input.Bindings [Description("Seek replay backward")] SeekReplayBackward, - [Description("Focus chat")] - FocusChatInput + [Description("Toggle chat focus")] + ToggleChatFocus } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 5d494379e6..e2f135d436 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -71,11 +71,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer { switch (action) { - case GlobalAction.FocusChatInput: - expandedFromTextboxFocus.Value = true; + case GlobalAction.ToggleChatFocus: + if (Textbox.HasFocus) + { + Schedule(() => Textbox.KillFocus()); + } + else + { + expandedFromTextboxFocus.Value = true; + + // schedule required to ensure the textbox has become present from above bindable update. + Schedule(() => Textbox.TakeFocus()); + } - // schedule required to ensure the textbox has become present from above bindable update. - Schedule(() => Textbox.TakeFocus()); return true; } From 6bfae25cda203f6bf5482281b7aa3f4568f52225 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 19 Aug 2021 08:30:27 +0300 Subject: [PATCH 473/961] Apply 5px vertical spacing on fill flow Regressed, was margin { bottom = 5f } from the star rating display creation method, which I've partly inlined. --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 1e1f362d71..17a26eb7ee 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -243,6 +243,7 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Top = 14, Right = shear_width / 2 }, AutoSizeAxes = Axes.Both, Shear = wedged_container_shear, + Spacing = new Vector2(0f, 5f), Children = new Drawable[] { starRatingDisplay = new StarRatingDisplay(default, animated: true) From 6469eaa427cf038725f05e93d88065e5f4135449 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 15:52:51 +0900 Subject: [PATCH 474/961] Fix background not updated in room --- .../Lounge/Components/DrawableRoom.cs | 10 +++--- .../OnlinePlay/Match/DrawableMatchRoom.cs | 2 ++ .../OnlinePlay/Match/RoomBackgroundSprite.cs | 33 +++++++++++++++++++ 3 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index c5b8bffbc6..bbec9aa21d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -61,7 +61,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [BackgroundDependencyLoader] private void load(OverlayColourProvider colours) { - InternalChildren = new Drawable[] + InternalChildren = new[] { // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. new Box @@ -69,10 +69,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components RelativeSizeAxes = Axes.Both, Colour = colours.Background5, }, - new OnlinePlayBackgroundSprite + CreateBackground().With(d => { - RelativeSizeAxes = Axes.Both - }, + d.RelativeSizeAxes = Axes.Both; + }), new Container { Name = @"Room content", @@ -264,6 +264,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components } } + protected virtual Drawable CreateBackground() => new OnlinePlayBackgroundSprite(); + private class RoomNameText : OsuSpriteText { [Resolved(typeof(Room), nameof(Online.Rooms.Room.Name))] diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index b3e6292f45..0924773338 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -58,5 +58,7 @@ namespace osu.Game.Screens.OnlinePlay.Match if (editButton != null) host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); } + + protected override Drawable CreateBackground() => new RoomBackgroundSprite(); } } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs new file mode 100644 index 0000000000..97262dd229 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs @@ -0,0 +1,33 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Beatmaps.Drawables; + +namespace osu.Game.Screens.OnlinePlay.Match +{ + public class RoomBackgroundSprite : RoomSubScreenComposite + { + protected readonly BeatmapSetCoverType BeatmapSetCoverType; + private UpdateableBeatmapBackgroundSprite sprite; + + public RoomBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) + { + BeatmapSetCoverType = beatmapSetCoverType; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChild = sprite = new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + SelectedItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true); + } + } +} From 1fd746524d1963f96333cec766110acc5cbc4e2f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:09:17 +0900 Subject: [PATCH 475/961] Remove realtime room category, fix end-date showing for realtime --- .../Visual/Multiplayer/TestSceneDrawableRoom.cs | 8 +------- osu.Game/Online/Rooms/RoomCategory.cs | 1 - .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 12 ++++++++++-- .../Multiplayer/MultiplayerLoungeSubScreen.cs | 1 - 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 489ece3271..8ca578b592 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -108,12 +108,6 @@ namespace osu.Game.Tests.Visual.Multiplayer EndDate = { Value = DateTimeOffset.Now }, }), createDrawableRoom(new Room - { - Name = { Value = "Room 4 (realtime)" }, - Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime }, - }), - createDrawableRoom(new Room { Name = { Value = "Room 4 (spotlight)" }, Status = { Value = new RoomStatusOpen() }, @@ -134,7 +128,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { Name = { Value = "Room with password" }, Status = { Value = new RoomStatusOpen() }, - Category = { Value = RoomCategory.Realtime }, + Type = { Value = MatchType.HeadToHead }, })); AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); diff --git a/osu.Game/Online/Rooms/RoomCategory.cs b/osu.Game/Online/Rooms/RoomCategory.cs index bb9f1298d3..a1dcfa5fd9 100644 --- a/osu.Game/Online/Rooms/RoomCategory.cs +++ b/osu.Game/Online/Rooms/RoomCategory.cs @@ -8,6 +8,5 @@ namespace osu.Game.Online.Rooms // used for osu-web deserialization so names shouldn't be changed. Normal, Spotlight, - Realtime, } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index bbec9aa21d..106211c833 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -34,12 +34,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected Container ButtonsContainer { get; private set; } + private readonly Bindable roomType = new Bindable(); private readonly Bindable roomCategory = new Bindable(); private readonly Bindable hasPassword = new Bindable(); private RecentParticipantsList recentParticipantsList; private RoomSpecialCategoryPill specialCategoryPill; private PasswordProtectedIcon passwordIcon; + private EndDateInfo endDateInfo; public DrawableRoom(Room room) { @@ -144,10 +146,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft }, - new EndDateInfo + endDateInfo = new EndDateInfo { Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft + Origin = Anchor.CentreLeft, }, } }, @@ -238,6 +240,12 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components specialCategoryPill.Hide(); }, true); + roomType.BindTo(Room.Type); + roomType.BindValueChanged(t => + { + endDateInfo.Alpha = t.NewValue == MatchType.Playlists ? 1 : 0; + }, true); + hasPassword.BindTo(Room.HasPassword); hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true); } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs index d152fc3913..6c3dfe7382 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerLoungeSubScreen.cs @@ -50,7 +50,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override Room CreateNewRoom() => new Room { Name = { Value = $"{api.LocalUser}'s awesome room" }, - Category = { Value = RoomCategory.Realtime }, Type = { Value = MatchType.HeadToHead }, }; From c31af96f1d18fb858bc4f5163439458e5dec2811 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:40:27 +0900 Subject: [PATCH 476/961] Pass room into RoomSettingsOverlay --- .../TestScenePlaylistsMatchSettingsOverlay.cs | 7 ++- .../Match/Components/RoomSettingsOverlay.cs | 11 +++-- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 ++- .../Match/MultiplayerMatchSettingsOverlay.cs | 44 +++++++++++-------- .../Multiplayer/MultiplayerMatchSubScreen.cs | 17 ++----- .../Playlists/PlaylistsRoomSettingsOverlay.cs | 29 +++++++----- .../Playlists/PlaylistsRoomSubScreen.cs | 4 +- 7 files changed, 66 insertions(+), 51 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs index 04b44efd32..48222e6b94 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsMatchSettingsOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Playlists { SelectedRoom.Value = new Room(); - Child = settings = new TestRoomSettings + Child = settings = new TestRoomSettings(SelectedRoom.Value) { RelativeSizeAxes = Axes.Both, State = { Value = Visibility.Visible } @@ -118,6 +118,11 @@ namespace osu.Game.Tests.Visual.Playlists public OsuDropdown DurationField => ((MatchSettings)Settings).DurationField; public OsuSpriteText ErrorText => ((MatchSettings)Settings).ErrorText; + + public TestRoomSettings(Room room) + : base(room) + { + } } private class TestDependencies : OnlinePlayTestSceneDependencies diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs index 80a22880d4..7a8839cdad 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/RoomSettingsOverlay.cs @@ -9,6 +9,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; +using osu.Game.Online.Rooms; using osuTK; using osuTK.Graphics; @@ -27,8 +28,12 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components protected abstract bool IsLoading { get; } - protected RoomSettingsOverlay() + private readonly Room room; + + protected RoomSettingsOverlay(Room room) { + this.room = room; + RelativeSizeAxes = Axes.Both; Masking = true; CornerRadius = 10; @@ -37,12 +42,12 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components [BackgroundDependencyLoader] private void load() { - Add(Settings = CreateSettings()); + Add(Settings = CreateSettings(room)); } protected abstract void SelectBeatmap(); - protected abstract OnlinePlayComposite CreateSettings(); + protected abstract OnlinePlayComposite CreateSettings(Room room); protected override void PopIn() { diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 81fae558c8..389eba0d82 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -184,7 +184,7 @@ namespace osu.Game.Screens.OnlinePlay.Match RelativeSizeAxes = Axes.Both, // Resolves 1px masking errors between the settings overlay and the room panel. Padding = new MarginPadding(-1), - Child = settingsOverlay = CreateRoomSettingsOverlay() + Child = settingsOverlay = CreateRoomSettingsOverlay(Room) } }, }, @@ -406,7 +406,8 @@ namespace osu.Game.Screens.OnlinePlay.Match /// /// Creates the room settings overlay. /// - protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(); + /// + protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); private class UserModSelectOverlay : LocalPlayerModSelectOverlay { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs index 3a95ac00a6..cd78a94765 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchSettingsOverlay.cs @@ -37,15 +37,19 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match protected override bool IsLoading => ongoingOperationTracker.InProgress.Value; + public MultiplayerMatchSettingsOverlay(Room room) + : base(room) + { + } + protected override void SelectBeatmap() => settings.SelectBeatmap(); - protected override OnlinePlayComposite CreateSettings() - => settings = new MatchSettings - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y, - SettingsApplied = Hide - }; + protected override OnlinePlayComposite CreateSettings(Room room) => settings = new MatchSettings(room) + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Y, + SettingsApplied = Hide + }; protected class MatchSettings : OnlinePlayComposite { @@ -73,9 +77,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [Resolved] private MultiplayerClient client { get; set; } - [Resolved] - private Bindable currentRoom { get; set; } - [Resolved] private Bindable beatmap { get; set; } @@ -90,6 +91,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [CanBeNull] private IDisposable applyingSettingsOperation; + private readonly Room room; + + public MatchSettings(Room room) + { + this.room = room; + } + [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -319,24 +327,24 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match client.ChangeSettings(name: NameField.Text, password: PasswordTextBox.Text, matchType: TypePicker.Current.Value).ContinueWith(t => Schedule(() => { if (t.IsCompletedSuccessfully) - onSuccess(currentRoom.Value); + onSuccess(room); else onError(t.Exception?.AsSingular().Message ?? "Error changing settings."); })); } else { - currentRoom.Value.Name.Value = NameField.Text; - currentRoom.Value.Availability.Value = AvailabilityPicker.Current.Value; - currentRoom.Value.Type.Value = TypePicker.Current.Value; - currentRoom.Value.Password.Value = PasswordTextBox.Current.Value; + room.Name.Value = NameField.Text; + room.Availability.Value = AvailabilityPicker.Current.Value; + room.Type.Value = TypePicker.Current.Value; + room.Password.Value = PasswordTextBox.Current.Value; if (int.TryParse(MaxParticipantsField.Text, out int max)) - currentRoom.Value.MaxParticipants.Value = max; + room.MaxParticipants.Value = max; else - currentRoom.Value.MaxParticipants.Value = null; + room.MaxParticipants.Value = null; - manager?.CreateRoom(currentRoom.Value, onSuccess, onError); + manager?.CreateRoom(room, onSuccess, onError); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 3f5837cbbe..833e6b24e0 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -48,9 +48,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer [Resolved] private OngoingOperationTracker ongoingOperationTracker { get; set; } - [Resolved] - private Bindable currentRoom { get; set; } // Todo: This should not exist. - private readonly IBindable isConnected = new Bindable(); [CanBeNull] @@ -82,16 +79,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer handleRoomLost(); }, true); - currentRoom.BindValueChanged(room => - { - if (room.NewValue == null) - { - // the room has gone away. - // this could mean something happened during the join process, or an external connection issue occurred. - // one specific scenario is where the underlying room is created, but the signalr server returns an error during the join process. this triggers a PartRoom operation (see https://github.com/ppy/osu/blob/7654df94f6f37b8382be7dfcb4f674e03bd35427/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomManager.cs#L97) - handleRoomLost(); - } - }, true); + if (client.Room == null) + handleRoomLost(); } protected override Drawable CreateMainContent() => new GridContainer @@ -223,7 +212,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer OnSpectateClick = onSpectateClick }; - protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new MultiplayerMatchSettingsOverlay(); + protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new MultiplayerMatchSettingsOverlay(room); protected override void UpdateMods() { diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs index 3eea59006a..7384c60888 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSettingsOverlay.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Specialized; using Humanizer; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -32,15 +31,19 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override bool IsLoading => settings.IsLoading; // should probably be replaced with an OngoingOperationTracker. + public PlaylistsRoomSettingsOverlay(Room room) + : base(room) + { + } + protected override void SelectBeatmap() => settings.SelectBeatmap(); - protected override OnlinePlayComposite CreateSettings() - => settings = new MatchSettings - { - RelativeSizeAxes = Axes.Both, - RelativePositionAxes = Axes.Y, - EditPlaylist = () => EditPlaylist?.Invoke() - }; + protected override OnlinePlayComposite CreateSettings(Room room) => settings = new MatchSettings(room) + { + RelativeSizeAxes = Axes.Both, + RelativePositionAxes = Axes.Y, + EditPlaylist = () => EditPlaylist?.Invoke() + }; protected class MatchSettings : OnlinePlayComposite { @@ -66,8 +69,12 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved(CanBeNull = true)] private IRoomManager manager { get; set; } - [Resolved] - private Bindable currentRoom { get; set; } + private readonly Room room; + + public MatchSettings(Room room) + { + this.room = room; + } [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -333,7 +340,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Duration.Value = DurationField.Current.Value; - manager?.CreateRoom(currentRoom.Value, onSuccess, onError); + manager?.CreateRoom(room, onSuccess, onError); loadingLayer.Show(); } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 27de781d5f..cd38e658a2 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -50,7 +50,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists if (idleTracker != null) isIdle.BindTo(idleTracker.IsIdle); - AddInternal(selectionPollingComponent = new SelectionPollingComponent()); + AddInternal(selectionPollingComponent = new SelectionPollingComponent(Room)); } protected override void LoadComplete() @@ -183,7 +183,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists OnStart = StartPlay }; - protected override RoomSettingsOverlay CreateRoomSettingsOverlay() => new PlaylistsRoomSettingsOverlay + protected override RoomSettingsOverlay CreateRoomSettingsOverlay(Room room) => new PlaylistsRoomSettingsOverlay(room) { EditPlaylist = () => { From 3a1154c00e85c834789d2e4772d0efc8017c1ba3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:40:39 +0900 Subject: [PATCH 477/961] Pass room into SelectionPollingComponent --- .../Components/SelectionPollingComponent.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs index 88d9469f8c..0769d0747b 100644 --- a/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/SelectionPollingComponent.cs @@ -3,7 +3,6 @@ using System.Threading.Tasks; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Game.Online.Rooms; namespace osu.Game.Screens.OnlinePlay.Components @@ -13,20 +12,14 @@ namespace osu.Game.Screens.OnlinePlay.Components /// public class SelectionPollingComponent : RoomPollingComponent { - [Resolved] - private Bindable selectedRoom { get; set; } - [Resolved] private IRoomManager roomManager { get; set; } - [BackgroundDependencyLoader] - private void load() + private readonly Room room; + + public SelectionPollingComponent(Room room) { - selectedRoom.BindValueChanged(_ => - { - if (IsLoaded) - PollImmediately(); - }); + this.room = room; } private GetRoomRequest pollReq; @@ -36,13 +29,13 @@ namespace osu.Game.Screens.OnlinePlay.Components if (!API.IsLoggedIn) return base.Poll(); - if (selectedRoom.Value?.RoomID.Value == null) + if (room.RoomID.Value == null) return base.Poll(); var tcs = new TaskCompletionSource(); pollReq?.Cancel(); - pollReq = new GetRoomRequest(selectedRoom.Value.RoomID.Value.Value); + pollReq = new GetRoomRequest(room.RoomID.Value.Value); pollReq.Success += result => { From 00be7f4cca50f5136a5c73d024b9eaa47cbcae4d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:49:08 +0900 Subject: [PATCH 478/961] Make RoomsContainer/DrawableRoom not resolve via DI --- .../Multiplayer/TestSceneDrawableRoom.cs | 11 ++++--- .../TestSceneLoungeRoomsContainer.cs | 1 + .../Lounge/Components/RoomsContainer.cs | 31 ++++++++----------- .../OnlinePlay/Lounge/DrawableLoungeRoom.cs | 15 +++++---- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 3 +- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 8ca578b592..3973dc57b2 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -24,12 +24,11 @@ namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneDrawableRoom : OsuTestScene { - [Cached] - private readonly Bindable selectedRoom = new Bindable(); - [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + private readonly Bindable selectedRoom = new Bindable(); + [Test] public void TestMultipleStatuses() { @@ -153,7 +152,11 @@ namespace osu.Game.Tests.Visual.Multiplayer })); } - return new DrawableLoungeRoom(room) { MatchingFilter = true }; + return new DrawableLoungeRoom(room) + { + MatchingFilter = true, + SelectedRoom = { BindTarget = selectedRoom } + }; } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs index b23638e514..66298e9b3d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomsContainer.cs @@ -30,6 +30,7 @@ namespace osu.Game.Tests.Visual.Multiplayer Anchor = Anchor.Centre, Origin = Anchor.Centre, Width = 0.5f, + SelectedRoom = { BindTarget = SelectedRoom } }; }); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index be5558ed0b..76cb02199b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -23,16 +23,13 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { public class RoomsContainer : CompositeDrawable, IKeyBindingHandler { - private readonly IBindableList rooms = new BindableList(); - - private readonly FillFlowContainer roomFlow; + public readonly Bindable SelectedRoom = new Bindable(); + public readonly Bindable Filter = new Bindable(); public IReadOnlyList Rooms => roomFlow.FlowingChildren.Cast().ToArray(); - public readonly Bindable Filter = new Bindable(); - - [Resolved] - private Bindable selectedRoom { get; set; } + private readonly IBindableList rooms = new BindableList(); + private readonly FillFlowContainer roomFlow; [Resolved] private IRoomManager roomManager { get; set; } @@ -112,9 +109,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void addRooms(IEnumerable rooms) { foreach (var room in rooms) - { - roomFlow.Add(new DrawableLoungeRoom(room)); - } + roomFlow.Add(new DrawableLoungeRoom(room) { SelectedRoom = { BindTarget = SelectedRoom } }); applyFilterCriteria(Filter?.Value); } @@ -126,8 +121,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components roomFlow.RemoveAll(d => d.Room == r); // selection may have a lease due to being in a sub screen. - if (!selectedRoom.Disabled) - selectedRoom.Value = null; + if (!SelectedRoom.Disabled) + SelectedRoom.Value = null; } } @@ -139,8 +134,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override bool OnClick(ClickEvent e) { - if (!selectedRoom.Disabled) - selectedRoom.Value = null; + if (!SelectedRoom.Disabled) + SelectedRoom.Value = null; return base.OnClick(e); } @@ -202,26 +197,26 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void selectNext(int direction) { - if (selectedRoom.Disabled) + if (SelectedRoom.Disabled) return; var visibleRooms = Rooms.AsEnumerable().Where(r => r.IsPresent); Room room; - if (selectedRoom.Value == null) + if (SelectedRoom.Value == null) room = visibleRooms.FirstOrDefault()?.Room; else { if (direction < 0) visibleRooms = visibleRooms.Reverse(); - room = visibleRooms.SkipWhile(r => r.Room != selectedRoom.Value).Skip(1).FirstOrDefault()?.Room; + room = visibleRooms.SkipWhile(r => r.Room != SelectedRoom.Value).Skip(1).FirstOrDefault()?.Room; } // we already have a valid selection only change selection if we still have a room to switch to. if (room != null) - selectedRoom.Value = room; + SelectedRoom.Value = room; } #endregion diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 4e106b844c..7ff3298829 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -34,11 +34,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private const float transition_duration = 60; private const float selection_border_width = 4; - [Resolved(canBeNull: true)] - private LoungeSubScreen lounge { get; set; } + public readonly Bindable SelectedRoom = new Bindable(); [Resolved(canBeNull: true)] - private Bindable selectedRoom { get; set; } + private LoungeSubScreen lounge { get; set; } private Sample sampleSelect; private Sample sampleJoin; @@ -89,7 +88,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge else Alpha = 0; - selectedRoom.BindValueChanged(updateSelectedRoom, true); + SelectedRoom.BindValueChanged(updateSelectedRoom, true); } private void updateSelectedRoom(ValueChangedEvent selected) @@ -135,7 +134,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public bool OnPressed(GlobalAction action) { - if (selectedRoom.Value != Room) + if (SelectedRoom.Value != Room) return false; switch (action) @@ -152,14 +151,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { } - protected override bool ShouldBeConsideredForInput(Drawable child) => selectedRoom.Value == Room || child is HoverSounds; + protected override bool ShouldBeConsideredForInput(Drawable child) => SelectedRoom.Value == Room || child is HoverSounds; protected override bool OnClick(ClickEvent e) { - if (Room != selectedRoom.Value) + if (Room != SelectedRoom.Value) { sampleSelect?.Play(); - selectedRoom.Value = Room; + SelectedRoom.Value = Room; return true; } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 8bed3d6049..677b9c0782 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -159,7 +159,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge ScrollbarOverlapsContent = false, Child = roomsContainer = new RoomsContainer { - Filter = { BindTarget = filter } + Filter = { BindTarget = filter }, + SelectedRoom = { BindTarget = selectedRoom } } }, } From 4d1897c6b42f54657ef0025df8526c1ea1ff9477 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:49:53 +0900 Subject: [PATCH 479/961] Remove unnecessary resolve into ListingPollingComponent --- .../Screens/OnlinePlay/Components/ListingPollingComponent.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs index 1387b5a671..daac6a66cd 100644 --- a/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs +++ b/osu.Game/Screens/OnlinePlay/Components/ListingPollingComponent.cs @@ -20,9 +20,6 @@ namespace osu.Game.Screens.OnlinePlay.Components public readonly Bindable Filter = new Bindable(); - [Resolved] - private Bindable selectedRoom { get; set; } - [BackgroundDependencyLoader] private void load() { From 6b6d52c23b99fd981725d6f79ea41e4210a75735 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 16:53:07 +0900 Subject: [PATCH 480/961] Add dependency container to RoomSubScreen --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 389eba0d82..487ec9bb49 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -239,6 +239,14 @@ namespace osu.Game.Screens.OnlinePlay.Match UserMods.BindValueChanged(_ => Scheduler.AddOnce(UpdateMods)); } + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + return new CachedModelDependencyContainer(base.CreateChildDependencies(parent)) + { + Model = { Value = Room } + }; + } + public override bool OnBackButton() { if (Room.RoomID.Value == null) From da8a1692d9cbdcf8ba24dde2ac30e43cfc6ccf11 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 17:40:59 +0900 Subject: [PATCH 481/961] Add test coverage of multiplayer room/state messagepack serialisation --- ...TestMultiplayerMessagePackSerialization.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs diff --git a/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs b/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs new file mode 100644 index 0000000000..5491774e26 --- /dev/null +++ b/osu.Game.Tests/Online/TestMultiplayerMessagePackSerialization.cs @@ -0,0 +1,72 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using MessagePack; +using NUnit.Framework; +using osu.Game.Online; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; + +namespace osu.Game.Tests.Online +{ + [TestFixture] + public class TestMultiplayerMessagePackSerialization + { + [Test] + public void TestSerialiseRoom() + { + var room = new MultiplayerRoom(1) + { + MatchState = new TeamVersusRoomState() + }; + + var serialized = MessagePackSerializer.Serialize(room); + + var deserialized = MessagePackSerializer.Deserialize(serialized); + + Assert.IsTrue(deserialized.MatchState is TeamVersusRoomState); + } + + [Test] + public void TestSerialiseUserStateExpected() + { + var state = new TeamVersusUserState(); + + var serialized = MessagePackSerializer.Serialize(typeof(MatchUserState), state); + var deserialized = MessagePackSerializer.Deserialize(serialized); + + Assert.IsTrue(deserialized is TeamVersusUserState); + } + + [Test] + public void TestSerialiseUnionFailsWithSingalR() + { + var state = new TeamVersusUserState(); + + // SignalR serialises using the actual type, rather than a base specification. + var serialized = MessagePackSerializer.Serialize(typeof(TeamVersusUserState), state); + + // works with explicit type specified. + MessagePackSerializer.Deserialize(serialized); + + // fails with base (union) type. + Assert.Throws(() => MessagePackSerializer.Deserialize(serialized)); + } + + [Test] + public void TestSerialiseUnionSucceedsWithWorkaround() + { + var state = new TeamVersusUserState(); + + // SignalR serialises using the actual type, rather than a base specification. + var serialized = MessagePackSerializer.Serialize(typeof(TeamVersusUserState), state, SignalRUnionWorkaroundResolver.OPTIONS); + + // works with explicit type specified. + MessagePackSerializer.Deserialize(serialized); + + // works with custom resolver. + var deserialized = MessagePackSerializer.Deserialize(serialized, SignalRUnionWorkaroundResolver.OPTIONS); + Assert.IsTrue(deserialized is TeamVersusUserState); + } + } +} From fa01e4fad2ba730ee7e0d73c47d3f929ec979b7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 17:41:50 +0900 Subject: [PATCH 482/961] Add workaround for SignalR union serialisation --- osu.Game/Online/HubClientConnector.cs | 7 ++- .../Online/SignalRUnionWorkaroundResolver.cs | 61 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Online/SignalRUnionWorkaroundResolver.cs diff --git a/osu.Game/Online/HubClientConnector.cs b/osu.Game/Online/HubClientConnector.cs index d2dba8a402..e9d6960c71 100644 --- a/osu.Game/Online/HubClientConnector.cs +++ b/osu.Game/Online/HubClientConnector.cs @@ -148,7 +148,12 @@ namespace osu.Game.Online }); if (RuntimeInfo.SupportsJIT && preferMessagePack) - builder.AddMessagePackProtocol(); + { + builder.AddMessagePackProtocol(options => + { + options.SerializerOptions = SignalRUnionWorkaroundResolver.OPTIONS; + }); + } else { // eventually we will precompile resolvers for messagepack, but this isn't working currently diff --git a/osu.Game/Online/SignalRUnionWorkaroundResolver.cs b/osu.Game/Online/SignalRUnionWorkaroundResolver.cs new file mode 100644 index 0000000000..e44da044cc --- /dev/null +++ b/osu.Game/Online/SignalRUnionWorkaroundResolver.cs @@ -0,0 +1,61 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using MessagePack; +using MessagePack.Formatters; +using MessagePack.Resolvers; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; + +namespace osu.Game.Online +{ + /// + /// Handles SignalR being unable to comprehend [Union] types correctly by redirecting to a known base (union) type. + /// See https://github.com/dotnet/aspnetcore/issues/7298. + /// + public class SignalRUnionWorkaroundResolver : IFormatterResolver + { + public static readonly MessagePackSerializerOptions OPTIONS = + MessagePackSerializerOptions.Standard.WithResolver(new SignalRUnionWorkaroundResolver()); + + private static readonly Dictionary formatter_map = new Dictionary + { + { typeof(TeamVersusUserState), new TypeRedirectingFormatter() }, + { typeof(TeamVersusRoomState), new TypeRedirectingFormatter() }, + { typeof(ChangeTeamRequest), new TypeRedirectingFormatter() }, + + // These should not be required. The fallback should work. But something is weird with the way caching is done. + // For future adventurers, I would not advise looking into this further. It's likely not worth the effort. + { typeof(MatchUserState), new TypeRedirectingFormatter() }, + { typeof(MatchRoomState), new TypeRedirectingFormatter() }, + { typeof(MatchUserRequest), new TypeRedirectingFormatter() }, + { typeof(MatchServerEvent), new TypeRedirectingFormatter() }, + }; + + public IMessagePackFormatter GetFormatter() + { + if (formatter_map.TryGetValue(typeof(T), out var formatter)) + return (IMessagePackFormatter)formatter; + + return StandardResolver.Instance.GetFormatter(); + } + + public class TypeRedirectingFormatter : IMessagePackFormatter + { + private readonly IMessagePackFormatter baseFormatter; + + public TypeRedirectingFormatter() + { + baseFormatter = StandardResolver.Instance.GetFormatter(); + } + + public void Serialize(ref MessagePackWriter writer, TActual value, MessagePackSerializerOptions options) => + baseFormatter.Serialize(ref writer, (TBase)(object)value, StandardResolver.Options); + + public TActual Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => + (TActual)(object)baseFormatter.Deserialize(ref reader, StandardResolver.Options); + } + } +} From f95c6f0de5b484e1502ac06b2478069dabe9f275 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 17:42:13 +0900 Subject: [PATCH 483/961] Switch multiplayer back to messagepack --- osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs index c38a648a6a..965674c2f2 100644 --- a/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs @@ -39,7 +39,7 @@ namespace osu.Game.Online.Multiplayer { // Importantly, we are intentionally not using MessagePack here to correctly support derived class serialization. // More information on the limitations / reasoning can be found in osu-server-spectator's initialisation code. - connector = api.GetHubConnector(nameof(OnlineMultiplayerClient), endpoint, false); + connector = api.GetHubConnector(nameof(OnlineMultiplayerClient), endpoint); if (connector != null) { From 2b5a42e06325d0f1188be1bef1c0937cb569308e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 17:42:26 +0900 Subject: [PATCH 484/961] Add missing union specification for `MatchUserRequest` --- osu.Game/Online/Multiplayer/MatchUserRequest.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Multiplayer/MatchUserRequest.cs b/osu.Game/Online/Multiplayer/MatchUserRequest.cs index 15c3ad0776..8c6809e7f3 100644 --- a/osu.Game/Online/Multiplayer/MatchUserRequest.cs +++ b/osu.Game/Online/Multiplayer/MatchUserRequest.cs @@ -3,6 +3,7 @@ using System; using MessagePack; +using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus; namespace osu.Game.Online.Multiplayer { @@ -11,6 +12,7 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] + [Union(0, typeof(ChangeTeamRequest))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. public abstract class MatchUserRequest { } From bc025efce57932a0dd28ba0e21683bfa1b8dd85e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 17:42:44 +0900 Subject: [PATCH 485/961] Add commenting regarding workaround to avoid potential omission in the future --- osu.Game/Online/Multiplayer/MatchRoomState.cs | 6 +++--- osu.Game/Online/Multiplayer/MatchUserState.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MatchRoomState.cs b/osu.Game/Online/Multiplayer/MatchRoomState.cs index 5b662af100..edd34fb5a3 100644 --- a/osu.Game/Online/Multiplayer/MatchRoomState.cs +++ b/osu.Game/Online/Multiplayer/MatchRoomState.cs @@ -15,9 +15,9 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - [Union(0, typeof(TeamVersusRoomState))] - // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. - public class MatchRoomState + [Union(0, typeof(TeamVersusRoomState))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. + // TODO: abstract breaks json serialisation. attention will be required for iOS support (unless we get messagepack AOT working instead). + public abstract class MatchRoomState { } } diff --git a/osu.Game/Online/Multiplayer/MatchUserState.cs b/osu.Game/Online/Multiplayer/MatchUserState.cs index f457191bb5..69245deba0 100644 --- a/osu.Game/Online/Multiplayer/MatchUserState.cs +++ b/osu.Game/Online/Multiplayer/MatchUserState.cs @@ -15,9 +15,9 @@ namespace osu.Game.Online.Multiplayer /// [Serializable] [MessagePackObject] - [Union(0, typeof(TeamVersusUserState))] - // TODO: this will need to be abstract or interface when/if we get messagepack working. for now it isn't as it breaks json serialisation. - public class MatchUserState + [Union(0, typeof(TeamVersusUserState))] // IMPORTANT: Add rules to SignalRUnionWorkaroundResolver for new derived types. + // TODO: abstract breaks json serialisation. attention will be required for iOS support (unless we get messagepack AOT working instead). + public abstract class MatchUserState { } } From 4d1582d721e0af061117f2ad49fded615be7f003 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 18:14:45 +0900 Subject: [PATCH 486/961] Play settings hide animation if visible when exiting `RoomSubScreen` --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 81fae558c8..ec56edaa4d 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -244,6 +244,7 @@ namespace osu.Game.Screens.OnlinePlay.Match if (Room.RoomID.Value == null) { // room has not been created yet; exit immediately. + settingsOverlay.Hide(); return base.OnBackButton(); } From 493f47787b5c9a2bc3366b6ea55f8dc8269f6079 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 18:18:42 +0900 Subject: [PATCH 487/961] Disable condition for the time being --- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 833e6b24e0..61cb040830 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -79,8 +79,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer handleRoomLost(); }, true); - if (client.Room == null) - handleRoomLost(); + // if (client.Room == null) + // handleRoomLost(); } protected override Drawable CreateMainContent() => new GridContainer From 023f3fb70e263f6496066a0f399c978dae5e801b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 18:19:31 +0900 Subject: [PATCH 488/961] Use BackgroundScreen for multiplayer backgrounds --- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 3 + .../Screens/OnlinePlay/OnlinePlayScreen.cs | 61 ------------------- .../Screens/OnlinePlay/OnlinePlaySubScreen.cs | 9 ++- .../OnlinePlay/OnlinePlaySubScreenStack.cs | 14 +++++ 4 files changed, 25 insertions(+), 62 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 677b9c0782..7712e7d734 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -23,6 +23,7 @@ using osu.Game.Input; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; +using osu.Game.Screens.Backgrounds; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; @@ -36,6 +37,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; + protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); + protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); protected Container Buttons { get; } = new Container diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index e5962db608..c057c814ca 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -78,32 +78,16 @@ namespace osu.Game.Screens.OnlinePlay [BackgroundDependencyLoader] private void load() { - var backgroundColour = Color4Extensions.FromHex(@"3e3a44"); - InternalChild = waves = new MultiplayerWaveContainer { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = backgroundColour, - }, new Container { RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new BeatmapBackgroundSprite - { - RelativeSizeAxes = Axes.Both - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f)) - }, screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both @@ -276,51 +260,6 @@ namespace osu.Game.Screens.OnlinePlay } } - private class BeatmapBackgroundSprite : OnlinePlayBackgroundSprite - { - protected override UpdateableBeatmapBackgroundSprite CreateBackgroundSprite() => new BlurredBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; - - public class BlurredBackgroundSprite : UpdateableBeatmapBackgroundSprite - { - public BlurredBackgroundSprite(BeatmapSetCoverType type) - : base(type) - { - } - - protected override double LoadDelay => 200; - - protected override Drawable CreateDrawable(BeatmapInfo model) => - new BufferedLoader(base.CreateDrawable(model)); - } - - // This class is an unfortunate requirement due to `LongRunningLoad` requiring direct async loading. - // It means that if the web request fetching the beatmap background takes too long, it will suddenly appear. - internal class BufferedLoader : BufferedContainer - { - private readonly Drawable drawable; - - public BufferedLoader(Drawable drawable) - { - this.drawable = drawable; - - RelativeSizeAxes = Axes.Both; - BlurSigma = new Vector2(10); - FrameBufferScale = new Vector2(0.5f); - CacheDrawnFrameBuffer = true; - } - - [BackgroundDependencyLoader] - private void load() - { - LoadComponentAsync(drawable, d => - { - Add(d); - ForceRedraw(); - }); - } - } - } - ScreenStack IHasSubScreenStack.SubScreenStack => screenStack; } } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index e1bd889088..58531a4b1c 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -35,13 +35,16 @@ namespace osu.Game.Screens.OnlinePlay public override void OnEntering(IScreen last) { - this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint); + base.OnEntering(last); + this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint); this.MoveToX(X_SHIFT).MoveToX(0, X_MOVE_DURATION, Easing.OutQuint); } public override bool OnExiting(IScreen next) { + base.OnExiting(next); + this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); this.MoveToX(X_SHIFT, X_MOVE_DURATION, Easing.OutQuint); @@ -50,12 +53,16 @@ namespace osu.Game.Screens.OnlinePlay public override void OnResuming(IScreen last) { + base.OnResuming(last); + this.Delay(RESUME_TRANSITION_DELAY).FadeIn(APPEAR_DURATION, Easing.OutQuint); this.MoveToX(0, X_MOVE_DURATION, Easing.OutQuint); } public override void OnSuspending(IScreen next) { + base.OnSuspending(next); + this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); this.MoveToX(-X_SHIFT, X_MOVE_DURATION, Easing.OutQuint); } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs index 7f2a0980c1..69fa3b0916 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs @@ -1,12 +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.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; +using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { public class OnlinePlaySubScreenStack : OsuScreenStack { + public OnlinePlaySubScreenStack() + { + AddInternal(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f)) + }); + } + protected override void ScreenChanged(IScreen prev, IScreen next) { base.ScreenChanged(prev, next); From 4afc808ffcf32c1930f7a1bd256b62926b6c65e3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 18:25:40 +0900 Subject: [PATCH 489/961] Remove horizontal transitions for now They look bad with the current toolbar implementation. We can probably add them back once the toolbar is moved to the lounge. --- osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index e1bd889088..49cc77a5d8 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -23,12 +23,6 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both; } - public const float X_SHIFT = 200; - - public const double X_MOVE_DURATION = 800; - - public const double RESUME_TRANSITION_DELAY = DISAPPEAR_DURATION / 2; - public const double APPEAR_DURATION = 800; public const double DISAPPEAR_DURATION = 500; @@ -36,28 +30,23 @@ namespace osu.Game.Screens.OnlinePlay public override void OnEntering(IScreen last) { this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint); - this.FadeInFromZero(APPEAR_DURATION, Easing.OutQuint); - this.MoveToX(X_SHIFT).MoveToX(0, X_MOVE_DURATION, Easing.OutQuint); } public override bool OnExiting(IScreen next) { this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); - this.MoveToX(X_SHIFT, X_MOVE_DURATION, Easing.OutQuint); return false; } public override void OnResuming(IScreen last) { - this.Delay(RESUME_TRANSITION_DELAY).FadeIn(APPEAR_DURATION, Easing.OutQuint); - this.MoveToX(0, X_MOVE_DURATION, Easing.OutQuint); + this.FadeIn(APPEAR_DURATION, Easing.OutQuint); } public override void OnSuspending(IScreen next) { this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); - this.MoveToX(-X_SHIFT, X_MOVE_DURATION, Easing.OutQuint); } public override string ToString() => Title; From 675e2e34baf1d6796e96b7911bac786352538853 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:02:05 +0900 Subject: [PATCH 490/961] Add padding between beatmap panel and edit button --- .../OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 56b87302c2..2e94e51385 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Framework.Screens; using osu.Game.Online.API; using osu.Game.Screens.OnlinePlay.Match.Components; +using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { @@ -35,6 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, + Spacing = new Vector2(5), Children = new Drawable[] { beatmapPanelContainer = new Container From be774980440e89cbbc8451ef215138bf1a3046da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:02:31 +0900 Subject: [PATCH 491/961] Move chat to right column in multiplayer match screen --- .../Multiplayer/MultiplayerMatchSubScreen.cs | 106 ++++++++---------- 1 file changed, 47 insertions(+), 59 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 3f5837cbbe..6a41403aff 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -141,79 +141,67 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // Spacer null, // Main right column - new FillFlowContainer + new GridContainer { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new[] + RelativeSizeAxes = Axes.Both, + Content = new[] { - new FillFlowContainer + new Drawable[] { new OverlinedHeader("Beatmap") }, + new Drawable[] { new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } }, + new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] + UserModsSection = new FillFlowContainer { - new OverlinedHeader("Beatmap"), - new BeatmapSelectionControl { RelativeSizeAxes = Axes.X } - } - }, - UserModsSection = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Top = 10 }, - Children = new Drawable[] - { - new OverlinedHeader("Extra mods"), - new FillFlowContainer + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Top = 10 }, + Children = new Drawable[] { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] + new OverlinedHeader("Extra mods"), + new FillFlowContainer { - new UserModSelectButton + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Width = 90, - Text = "Select", - Action = ShowUserModSelect, - }, - new ModDisplay - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Current = UserMods, - Scale = new Vector2(0.8f), - }, - } + new UserModSelectButton + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Width = 90, + Text = "Select", + Action = ShowUserModSelect, + }, + new ModDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Current = UserMods, + Scale = new Vector2(0.8f), + }, + } + }, } - } - } + }, + }, + new Drawable[] { new OverlinedHeader("Chat") { Margin = new MarginPadding { Vertical = 5 }, }, }, + new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + new Dimension(), } - } + }, } } } } }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize) - }, - Content = new[] - { - new Drawable[] { new OverlinedHeader("Chat") }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } - } - } - } }, }; From 16aecfe934c9d893e694af1429ad0cede7c2d679 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:02:54 +0900 Subject: [PATCH 492/961] Start free mod selection area hidden on screen display --- .../Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 1 + osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 6a41403aff..3a012787a4 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -155,6 +155,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Top = 10 }, + Alpha = 0, Children = new Drawable[] { new OverlinedHeader("Extra mods"), diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 27de781d5f..729ddbef8c 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -120,6 +120,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, + Alpha = 0, Margin = new MarginPadding { Bottom = 10 }, Children = new Drawable[] { From 8fce5911a951dbe1cbc6884e0f596e2e5d50763b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:08:46 +0900 Subject: [PATCH 493/961] Adjust spacing and padding of footer buttons --- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 9 +++++++-- .../Multiplayer/Match/MultiplayerMatchFooter.cs | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index ec56edaa4d..10df7cbadc 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -195,14 +195,19 @@ namespace osu.Game.Screens.OnlinePlay.Match new Container { RelativeSizeAxes = Axes.Both, - Children = new[] + Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = Color4Extensions.FromHex(@"28242d") // Temporary. }, - CreateFooter() + new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(5), + Child = CreateFooter() + }, } } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs index 9e8d51e64e..036e37ddfd 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerMatchFooter.cs @@ -53,7 +53,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match { new Dimension(), new Dimension(maxSize: spectate_button_width), - new Dimension(GridSizeMode.Absolute, 10), + new Dimension(GridSizeMode.Absolute, 5), new Dimension(maxSize: ready_button_width), new Dimension() } From 44e157447c7d005079e2ede801ee6ad6fe5a802c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 19 Aug 2021 19:10:54 +0900 Subject: [PATCH 494/961] Initial rework of backgrounds --- .../Components/PlaylistItemBackground.cs | 44 ++++++++++ .../Components/RoomBackgroundScreen.cs | 82 +++++++++++++++++++ .../OnlinePlay/Lounge/LoungeSubScreen.cs | 6 +- .../Screens/OnlinePlay/OnlinePlayScreen.cs | 6 -- 4 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs create mode 100644 osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs diff --git a/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs new file mode 100644 index 0000000000..90ad6e0f6e --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/PlaylistItemBackground.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Textures; +using osu.Game.Beatmaps; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Online.Rooms; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public class PlaylistItemBackground : Background + { + public readonly BeatmapInfo? BeatmapInfo; + + public PlaylistItemBackground(PlaylistItem? playlistItem) + { + BeatmapInfo = playlistItem?.Beatmap.Value; + } + + [BackgroundDependencyLoader] + private void load(BeatmapManager beatmaps, LargeTextureStore textures) + { + Texture? texture = null; + + // prefer online cover where available. + if (BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers.Cover != null) + texture = textures.Get(BeatmapInfo.BeatmapSet.OnlineInfo.Covers.Cover); + + Sprite.Texture = texture ?? beatmaps.DefaultBeatmap.Background; + } + + public override bool Equals(Background? other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return other.GetType() == GetType() + && ((PlaylistItemBackground)other).BeatmapInfo == BeatmapInfo; + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs new file mode 100644 index 0000000000..c6e467233e --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs @@ -0,0 +1,82 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System.Linq; +using System.Threading; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Online.Rooms; +using osuTK; + +namespace osu.Game.Screens.OnlinePlay.Components +{ + public class RoomBackgroundScreen : BackgroundScreen + { + private CancellationTokenSource? cancellationSource; + private PlaylistItemBackground? background; + + private readonly BindableList playlist = new BindableList(); + + public RoomBackgroundScreen() + { + playlist.BindCollectionChanged((_, __) => updateBackground()); + } + + private Room? room; + + public Room? Room + { + get => room; + set + { + if (room == value) + return; + + if (room != null) + playlist.UnbindFrom(room.Playlist); + + room = value; + + if (room != null) + playlist.BindTo(room.Playlist); + else + playlist.Clear(); + } + } + + private void updateBackground() + { + Schedule(() => + { + var playlistItem = playlist.FirstOrDefault(); + var beatmap = playlistItem?.Beatmap.Value; + + if (background?.BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers?.Cover == beatmap?.BeatmapSet?.OnlineInfo?.Covers?.Cover) + return; + + cancellationSource?.Cancel(); + LoadComponentAsync(new PlaylistItemBackground(playlistItem), switchBackground, (cancellationSource = new CancellationTokenSource()).Token); + }); + } + + private void switchBackground(PlaylistItemBackground newBackground) + { + float newDepth = 0; + + if (background != null) + { + newDepth = background.Depth + 1; + background.FinishTransforms(); + background.FadeOut(250); + background.Expire(); + } + + newBackground.Depth = newDepth; + newBackground.BlurTo(new Vector2(10)); + + AddInternal(background = newBackground); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 7712e7d734..c5d9616ee3 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -23,7 +23,6 @@ using osu.Game.Input; using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Rulesets; -using osu.Game.Screens.Backgrounds; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; @@ -37,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; - protected override BackgroundScreen CreateBackground() => new BackgroundScreenDefault(); + protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen(); protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -180,6 +179,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge var drawable = roomsContainer.Rooms.FirstOrDefault(r => r.Room == val.NewValue); if (drawable != null) scrollContainer.ScrollIntoView(drawable); + + ApplyToBackground(b => ((RoomBackgroundScreen)b).Room = val.NewValue); }); } @@ -246,6 +247,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public override void OnEntering(IScreen last) { base.OnEntering(last); + onReturning(); } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index c057c814ca..576598cb1e 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -6,13 +6,9 @@ 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.Framework.Logging; using osu.Framework.Screens; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics.Containers; using osu.Game.Online.API; using osu.Game.Online.Rooms; @@ -21,8 +17,6 @@ using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Users; -using osuTK; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { From a65cd36a5f25296b5348f483208ad37458437841 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:19:46 +0900 Subject: [PATCH 495/961] Move some constants to `const`s --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 17a26eb7ee..297a16dd1d 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -73,17 +73,19 @@ namespace osu.Game.Screens.Select ruleset.BindValueChanged(_ => updateDisplay()); } + private const double animation_duration = 800; + protected override void PopIn() { - this.MoveToX(0, 800, Easing.OutQuint); - this.RotateTo(0, 800, Easing.OutQuint); + this.MoveToX(0, animation_duration, Easing.OutQuint); + this.RotateTo(0, animation_duration, Easing.OutQuint); this.FadeIn(transition_duration); } protected override void PopOut() { - this.MoveToX(-100, 800, Easing.In); - this.RotateTo(10, 800, Easing.In); + this.MoveToX(-100, animation_duration, Easing.In); + this.RotateTo(10, animation_duration, Easing.In); this.FadeOut(transition_duration * 2, Easing.In); } @@ -191,6 +193,8 @@ namespace osu.Game.Screens.Select titleBinding = localisation.GetLocalisedString(new RomanisableString(metadata.TitleUnicode, metadata.Title)); artistBinding = localisation.GetLocalisedString(new RomanisableString(metadata.ArtistUnicode, metadata.Artist)); + const float top_height = 0.7f; + Children = new Drawable[] { difficultyColourBar = new Container @@ -202,15 +206,15 @@ namespace osu.Game.Screens.Select new Box { RelativeSizeAxes = Axes.Both, - Width = 0.7f, + Width = top_height, }, new Box { RelativeSizeAxes = Axes.Both, RelativePositionAxes = Axes.Both, Alpha = 0.5f, - X = 0.7f, - Width = 1 - 0.7f, + X = top_height, + Width = 1 - top_height, } } }, From a6b7ca1a4c44a5f303abcf3c4c1cc59facdee905 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 19 Aug 2021 19:55:10 +0900 Subject: [PATCH 496/961] Ensure all request failures are correctly handled during login --- osu.Game/Online/API/APIAccess.cs | 4 ++-- osu.Game/Online/API/APIRequest.cs | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index f7a3f4602f..96d62e95a2 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -309,7 +309,7 @@ namespace osu.Game.Online.API if (IsLoggedIn) state.Value = APIState.Online; failureCount = 0; - return true; + return req.CompletionState == APIRequestCompletionState.Completed; } catch (HttpRequestException re) { @@ -381,7 +381,7 @@ namespace osu.Game.Online.API } } - public bool IsLoggedIn => localUser.Value.Id > 1; + public bool IsLoggedIn => localUser.Value.Id > 1; // TODO: should this also be true if attempting to connect? public void Queue(APIRequest request) { diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index e117293ce6..cf17ed4b5d 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -84,7 +84,7 @@ namespace osu.Game.Online.API /// The state of this request, from an outside perspective. /// This is used to ensure correct notification events are fired. /// - private APIRequestCompletionState completionState; + public APIRequestCompletionState CompletionState { get; private set; } public void Perform(IAPIProvider api) { @@ -127,10 +127,10 @@ namespace osu.Game.Online.API { lock (completionStateLock) { - if (completionState != APIRequestCompletionState.Waiting) + if (CompletionState != APIRequestCompletionState.Waiting) return; - completionState = APIRequestCompletionState.Completed; + CompletionState = APIRequestCompletionState.Completed; } if (API == null) @@ -143,10 +143,10 @@ namespace osu.Game.Online.API { lock (completionStateLock) { - if (completionState != APIRequestCompletionState.Waiting) + if (CompletionState != APIRequestCompletionState.Waiting) return; - completionState = APIRequestCompletionState.Failed; + CompletionState = APIRequestCompletionState.Failed; } if (API == null) @@ -161,7 +161,7 @@ namespace osu.Game.Online.API { lock (completionStateLock) { - if (completionState != APIRequestCompletionState.Waiting) + if (CompletionState != APIRequestCompletionState.Waiting) return; WebRequest?.Abort(); @@ -200,7 +200,7 @@ namespace osu.Game.Online.API get { lock (completionStateLock) - return completionState == APIRequestCompletionState.Failed; + return CompletionState == APIRequestCompletionState.Failed; } } From bf7f0a5d30fe779c308ec0299ee7a779a4aadbd8 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 19 Aug 2021 19:02:04 +0200 Subject: [PATCH 497/961] Remove double whitespace --- osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index c0460a4536..ad045c4b17 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -141,7 +141,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = BeatmapsetsStrings.ShowDetailsDownloadDefault, + Text = BeatmapsetsStrings.ShowDetailsDownloadDefault, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, new OsuSpriteText From 5f1948d040b054a4ec68e964166b2c61aedb2d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 19 Aug 2021 22:31:11 +0200 Subject: [PATCH 498/961] Add failing test case --- .../Visual/Settings/TestSceneSettingsItem.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs index df59b9284b..d9cce69ee3 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneSettingsItem.cs @@ -76,5 +76,23 @@ namespace osu.Game.Tests.Visual.Settings AddStep("restore default", () => sliderBar.Current.SetDefault()); AddUntilStep("restore button hidden", () => restoreDefaultValueButton.Alpha == 0); } + + [Test] + public void TestWarningTextVisibility() + { + SettingsNumberBox numberBox = null; + + AddStep("create settings item", () => Child = numberBox = new SettingsNumberBox()); + AddAssert("warning text not created", () => !numberBox.ChildrenOfType().Any()); + + AddStep("set warning text", () => numberBox.WarningText = "this is a warning!"); + AddAssert("warning text created", () => numberBox.ChildrenOfType().Single().Alpha == 1); + + AddStep("unset warning text", () => numberBox.WarningText = default); + AddAssert("warning text hidden", () => numberBox.ChildrenOfType().Single().Alpha == 0); + + AddStep("set warning text again", () => numberBox.WarningText = "another warning!"); + AddAssert("warning text shown again", () => numberBox.ChildrenOfType().Single().Alpha == 1); + } } } From 143b8df1b2018d1b5efb169581d199064780cdf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 19 Aug 2021 22:33:05 +0200 Subject: [PATCH 499/961] Fix backwards warning text presence check --- osu.Game/Overlays/Settings/SettingsItem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs index 6621caef4e..5282217013 100644 --- a/osu.Game/Overlays/Settings/SettingsItem.cs +++ b/osu.Game/Overlays/Settings/SettingsItem.cs @@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Settings { set { - bool hasValue = string.IsNullOrWhiteSpace(value.ToString()); + bool hasValue = !string.IsNullOrWhiteSpace(value.ToString()); if (warningText == null) { @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Settings FlowContent.Add(warningText = new SettingsNoticeText(colours) { Margin = new MarginPadding { Bottom = 5 } }); } - warningText.Alpha = hasValue ? 0 : 1; + warningText.Alpha = hasValue ? 1 : 0; warningText.Text = value.ToString(); // TODO: Remove ToString() call after TextFlowContainer supports localisation (see https://github.com/ppy/osu-framework/issues/4636). } } From 4d9c415e730ecc488d9b4f7a9758fc208ff4968c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 20 Aug 2021 04:37:35 +0300 Subject: [PATCH 500/961] Remove unnecessary queue in beatmap difficulty cache tests --- .../TestSceneBeatmapDifficultyCache.cs | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index b6ba5b748a..6856e466cf 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -32,7 +32,6 @@ namespace osu.Game.Tests.Beatmaps private TestBeatmapDifficultyCache difficultyCache; private IBindable starDifficultyBindable; - private Queue> starDifficultyChangesQueue; [BackgroundDependencyLoader] private void load(OsuGameBase osu) @@ -49,14 +48,10 @@ namespace osu.Game.Tests.Beatmaps Child = difficultyCache = new TestBeatmapDifficultyCache(); - starDifficultyChangesQueue = new Queue>(); starDifficultyBindable = difficultyCache.GetBindableDifficulty(importedSet.Beatmaps.First()); - starDifficultyBindable.BindValueChanged(starDifficultyChangesQueue.Enqueue); }); - AddAssert($"star difficulty -> {BASE_STARS}", () => - starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS && - starDifficultyChangesQueue.Count == 0); + AddAssert($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS); } [Test] @@ -65,19 +60,13 @@ namespace osu.Game.Tests.Beatmaps OsuModDoubleTime dt = null; AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); - AddAssert($"star difficulty -> {BASE_STARS + 1.5}", () => - starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.5 && - starDifficultyChangesQueue.Count == 0); + AddAssert($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5); AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25); - AddAssert($"star difficulty -> {BASE_STARS + 1.25}", () => - starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.25 && - starDifficultyChangesQueue.Count == 0); + AddAssert($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.25); AddStep("change selected mod to NC", () => SelectedMods.Value = new[] { new OsuModNightcore { SpeedChange = { Value = 1.75 } } }); - AddAssert($"star difficulty -> {BASE_STARS + 1.75}", () => - starDifficultyChangesQueue.Dequeue().NewValue?.Stars == BASE_STARS + 1.75 && - starDifficultyChangesQueue.Count == 0); + AddAssert($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75); } [Test] From d98742522b339b4c92a49406bd9df7fe052b4225 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 20 Aug 2021 04:40:03 +0300 Subject: [PATCH 501/961] Remove unused using directive --- osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index 6856e466cf..bdf4fb8d0c 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.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; using System.Threading.Tasks; From 73b40a6244abacb48bbf34f537f7ac11343c0e84 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 20 Aug 2021 05:29:30 +0300 Subject: [PATCH 502/961] Switch to until step to account for asynchronous operations --- .../Beatmaps/TestSceneBeatmapDifficultyCache.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index bdf4fb8d0c..da457c9e8f 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -50,7 +50,7 @@ namespace osu.Game.Tests.Beatmaps starDifficultyBindable = difficultyCache.GetBindableDifficulty(importedSet.Beatmaps.First()); }); - AddAssert($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS); + AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS); } [Test] @@ -59,13 +59,13 @@ namespace osu.Game.Tests.Beatmaps OsuModDoubleTime dt = null; AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); - AddAssert($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5); AddStep("change DT speed to 1.25", () => dt.SpeedChange.Value = 1.25); - AddAssert($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.25); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.25}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.25); AddStep("change selected mod to NC", () => SelectedMods.Value = new[] { new OsuModNightcore { SpeedChange = { Value = 1.75 } } }); - AddAssert($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75); + AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75); } [Test] From 1e6119da0b2cab68368f370dad96591478cf7a4a Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 20 Aug 2021 05:36:39 +0300 Subject: [PATCH 503/961] Update code inspection settings to hide "merge into pattern" again --- osu.sln.DotSettings | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index d884ea31c5..e42b30e944 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -105,8 +105,9 @@ HINT HINT WARNING + DO_NOT_SHOW + DO_NOT_SHOW WARNING - DO_NOT_SHOW WARNING WARNING WARNING From 2825e15fd4af729be343f3b029eb13be7e0f8f72 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 11:54:37 +0900 Subject: [PATCH 504/961] 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 24d07b4588..f74b5d410b 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 928620b32e..e4838dc95a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 77f9052e85..5338ad5deb 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 1e02d61b852762425553b7873ccf01eb15cb9060 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 19 Aug 2021 20:06:25 -0700 Subject: [PATCH 505/961] Fix nub glow color not having 0 alpha when being set --- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index cbf3e6b3aa..80d83e17c1 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -149,7 +149,7 @@ namespace osu.Game.Graphics.UserInterface glowColour = value; var effect = EdgeEffect; - effect.Colour = value; + effect.Colour = value.Opacity(0); EdgeEffect = effect; } } From da8eba999657826a8dd8a611f5c62576749f6b44 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 12:11:41 +0900 Subject: [PATCH 506/961] Return early to avoid updating state and failure count in fail cases --- osu.Game/Online/API/APIAccess.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index 96d62e95a2..af14cdc7b3 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -305,11 +305,13 @@ namespace osu.Game.Online.API { req.Perform(this); + if (req.CompletionState != APIRequestCompletionState.Completed) + return false; + // we could still be in initialisation, at which point we don't want to say we're Online yet. if (IsLoggedIn) state.Value = APIState.Online; - failureCount = 0; - return req.CompletionState == APIRequestCompletionState.Completed; + return true; } catch (HttpRequestException re) { From 284c871e39f4272d036547eceae8257bad7871c5 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Thu, 19 Aug 2021 20:33:19 -0700 Subject: [PATCH 507/961] Fix glow color potentially being set incorrectly when glowing Co-authored-by: Salman Ahmed --- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 80d83e17c1..664f32b083 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -149,7 +149,7 @@ namespace osu.Game.Graphics.UserInterface glowColour = value; var effect = EdgeEffect; - effect.Colour = value.Opacity(0); + effect.Colour = Glowing ? value : value.Opacity(0); EdgeEffect = effect; } } From 19cc4a14a36ce0ccb7d5f418e2a09c2a361887c5 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 20 Aug 2021 09:22:15 +0200 Subject: [PATCH 508/961] Localise top score mods statistics --- .../Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 582528b675..23069eccdf 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -235,7 +235,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } private ModsInfoColumn(FillFlowContainer modsContainer) - : base("mods", modsContainer) + : base(BeatmapsetsStrings.ShowScoreboardHeadersMods, modsContainer) { this.modsContainer = modsContainer; } From 0a1c9a6c05bd33adf8f73f1d9f3c39710ed65bc6 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 20 Aug 2021 09:26:38 +0200 Subject: [PATCH 509/961] Move DownloadButtonStrings -> CommonStrings --- osu.Game/Localisation/CommonStrings.cs | 12 +++++++++- .../Localisation/DownloadButtonStrings.cs | 24 ------------------- .../Buttons/HeaderDownloadButton.cs | 5 ++-- 3 files changed, 13 insertions(+), 28 deletions(-) delete mode 100644 osu.Game/Localisation/DownloadButtonStrings.cs diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index bf488d2590..b4381fc442 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -29,6 +29,16 @@ namespace osu.Game.Localisation /// public static LocalisableString Height => new TranslatableString(getKey(@"height"), @"Height"); + /// + /// "Downloading..." + /// + public static LocalisableString Downloading => new TranslatableString(getKey(@"downloading"), @"Downloading..."); + + /// + /// "Importing..." + /// + public static LocalisableString Importing => new TranslatableString(getKey(@"importing"), @"Importing..."); + private static string getKey(string key) => $@"{prefix}:{key}"; } -} \ No newline at end of file +} diff --git a/osu.Game/Localisation/DownloadButtonStrings.cs b/osu.Game/Localisation/DownloadButtonStrings.cs deleted file mode 100644 index 736f309624..0000000000 --- a/osu.Game/Localisation/DownloadButtonStrings.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation -{ - public static class DownloadButtonStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.DownloadButton"; - - /// - /// "Downloading..." - /// - public static LocalisableString Downloading => new TranslatableString(getKey(@"downloading"), @"Downloading..."); - - /// - /// "Importing..." - /// - public static LocalisableString Importing => new TranslatableString(getKey(@"importing"), @"Importing..."); - - private static string getKey(string key) => $@"{prefix}:{key}"; - } -} diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs index ad045c4b17..e7a55079ec 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderDownloadButton.cs @@ -19,7 +19,6 @@ using osu.Game.Resources.Localisation.Web; using osu.Game.Users; using osuTK; using osuTK.Graphics; -using osu.Game.Localisation; namespace osu.Game.Overlays.BeatmapSet.Buttons { @@ -115,7 +114,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = DownloadButtonStrings.Downloading, + Text = Localisation.CommonStrings.Downloading, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, }; @@ -126,7 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons { new OsuSpriteText { - Text = DownloadButtonStrings.Importing, + Text = Localisation.CommonStrings.Importing, Font = OsuFont.GetFont(size: text_size, weight: FontWeight.Bold) }, }; From 9b4c806855b2e4ce7371983a83f13e6c7f8d65d0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 20 Aug 2021 09:47:23 +0200 Subject: [PATCH 510/961] Apply review suggestions. --- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 27 +++++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 80dc185bb5..2dcb2f1777 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -81,10 +81,26 @@ namespace osu.Game.Overlays.BeatmapSet Direction = FillDirection.Horizontal, Children = new[] { - length = new Statistic(BeatmapStatisticsIconType.Length, BeatmapsetsStrings.ShowStatsTotalLength(string.Empty)) { Width = 0.25f }, - bpm = new Statistic(BeatmapStatisticsIconType.Bpm, BeatmapsetsStrings.ShowStatsBpm) { Width = 0.25f }, - circleCount = new Statistic(BeatmapStatisticsIconType.Circles, BeatmapsetsStrings.ShowStatsCountCircles) { Width = 0.25f }, - sliderCount = new Statistic(BeatmapStatisticsIconType.Sliders, BeatmapsetsStrings.ShowStatsCountSliders) { Width = 0.25f }, + length = new Statistic(BeatmapStatisticsIconType.Length) + { + Width = 0.25f, + TooltipText = default, + }, + bpm = new Statistic(BeatmapStatisticsIconType.Bpm) + { + Width = 0.25f, + TooltipText = BeatmapsetsStrings.ShowStatsBpm + }, + circleCount = new Statistic(BeatmapStatisticsIconType.Circles) + { + Width = 0.25f, + TooltipText = BeatmapsetsStrings.ShowStatsCountCircles + }, + sliderCount = new Statistic(BeatmapStatisticsIconType.Sliders) + { + Width = 0.25f, + TooltipText = BeatmapsetsStrings.ShowStatsCountSliders + }, }, }; } @@ -107,9 +123,8 @@ namespace osu.Game.Overlays.BeatmapSet set => this.value.Text = value; } - public Statistic(BeatmapStatisticsIconType icon, LocalisableString name) + public Statistic(BeatmapStatisticsIconType icon) { - TooltipText = name; RelativeSizeAxes = Axes.X; Height = 24f; From cff7b1e98f495b11c34d3d92850c7edfa9cd4e1a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 16:50:27 +0900 Subject: [PATCH 511/961] Ensure the correct fade level is applied over all state changes --- osu.Game/Overlays/Settings/SettingsSection.cs | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index 8d98ae484f..5c38dee356 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -102,28 +102,20 @@ namespace osu.Game.Overlays.Settings }); selectedSection = settingsPanel.CurrentSection.GetBoundCopy(); - selectedSection.BindValueChanged(selected => - { - if (selected.NewValue == this) - content.FadeIn(500, Easing.OutQuint); - else - content.FadeTo(0.25f, 500, Easing.OutQuint); - }, true); + selectedSection.BindValueChanged(_ => updateContentFade(), true); } private bool isCurrentSection => selectedSection.Value == this; protected override bool OnHover(HoverEvent e) { - if (!isCurrentSection) - content.FadeTo(0.6f, 500, Easing.OutQuint); + updateContentFade(); return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { - if (!isCurrentSection) - content.FadeTo(0.25f, 500, Easing.OutQuint); + updateContentFade(); base.OnHoverLost(e); } @@ -135,9 +127,19 @@ namespace osu.Game.Overlays.Settings return base.OnClick(e); } - protected override bool ShouldBeConsideredForInput(Drawable child) + protected override bool ShouldBeConsideredForInput(Drawable child) => + // only the current section should accept input. + // this provides the behaviour of the first click scrolling the target section to the centre of the screen. + isCurrentSection; + + private void updateContentFade() { - return isCurrentSection; + float targetFade = 1; + + if (!isCurrentSection) + targetFade = IsHovered ? 0.6f : 0.25f; + + content.FadeTo(targetFade, 500, Easing.OutQuint); } } } From c7266c74a09bcfdcdf94d95049f224d03a034397 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 17:00:20 +0900 Subject: [PATCH 512/961] Always prefer clicked section when present --- .../Graphics/Containers/SectionsContainer.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index e11d1e1300..4b368b98ad 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -23,7 +23,7 @@ namespace osu.Game.Graphics.Containers { public Bindable SelectedSection { get; } = new Bindable(); - private Drawable lastClickedSection; + private T lastClickedSection; public Drawable ExpandableHeader { @@ -145,10 +145,12 @@ namespace osu.Game.Graphics.Containers footerHeight = null; } - public void ScrollTo(Drawable section) + public void ScrollTo(Drawable target) { - lastClickedSection = section; - scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - scrollContainer.DisplayableContent * scroll_y_centre - (FixedHeader?.BoundingBox.Height ?? 0)); + if (target is T section) + lastClickedSection = section; + + scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(target) - scrollContainer.DisplayableContent * scroll_y_centre - (FixedHeader?.BoundingBox.Height ?? 0)); } public void ScrollToTop() => scrollContainer.ScrollTo(0); @@ -236,10 +238,12 @@ namespace osu.Game.Graphics.Containers var presentChildren = Children.Where(c => c.IsPresent); - if (Precision.AlmostBigger(0, scrollContainer.Current)) - SelectedSection.Value = lastClickedSection as T ?? presentChildren.FirstOrDefault(); + if (lastClickedSection != null) + SelectedSection.Value = lastClickedSection; + else if (Precision.AlmostBigger(0, scrollContainer.Current)) + SelectedSection.Value = presentChildren.FirstOrDefault(); else if (Precision.AlmostBigger(scrollContainer.Current, scrollContainer.ScrollableExtent)) - SelectedSection.Value = lastClickedSection as T ?? presentChildren.LastOrDefault(); + SelectedSection.Value = presentChildren.LastOrDefault(); else { SelectedSection.Value = presentChildren From 8524937c82c6bc504de2528748d8667e005e563f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 17:02:55 +0900 Subject: [PATCH 513/961] Move screenstack up a level --- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 576598cb1e..2e1d353d47 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -77,17 +77,7 @@ namespace osu.Game.Screens.OnlinePlay RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new Container - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - screenStack = new OnlinePlaySubScreenStack - { - RelativeSizeAxes = Axes.Both - } - } - }, + screenStack = new OnlinePlaySubScreenStack { RelativeSizeAxes = Axes.Both }, new Header(ScreenTitle, screenStack), RoomManager, ongoingOperationTracker From 3d96da84e6c3362fb6252cd086ec870050f72c1d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 17:05:46 +0900 Subject: [PATCH 514/961] Set a default background --- .../Screens/OnlinePlay/Components/RoomBackgroundScreen.cs | 8 ++++++++ osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 1 - 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs index c6e467233e..efcfa35e19 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Online.Rooms; @@ -20,10 +21,17 @@ namespace osu.Game.Screens.OnlinePlay.Components private readonly BindableList playlist = new BindableList(); public RoomBackgroundScreen() + : base(false) { playlist.BindCollectionChanged((_, __) => updateBackground()); } + [BackgroundDependencyLoader] + private void load() + { + switchBackground(new PlaylistItemBackground(null)); + } + private Room? room; public Room? Room diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 2e1d353d47..76815172e5 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -6,7 +6,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.Containers; From 139ff2d6e2a5a242ac2be92ba8737e81132d4f5c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 17:40:03 +0900 Subject: [PATCH 515/961] Only fade header in when hovering a section Feels less like the controls are interactive when hovering this way. --- osu.Game/Overlays/Settings/SettingsSection.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index 5c38dee356..6f167bf059 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Settings private IBindable selectedSection; - private Container content; + private OsuSpriteText header; public abstract Drawable CreateIcon(); public abstract LocalisableString Header { get; } @@ -70,11 +70,12 @@ namespace osu.Game.Overlays.Settings { new Box { + Name = "separator", Colour = new Color4(0, 0, 0, 255), RelativeSizeAxes = Axes.X, Height = border_size, }, - content = new Container + new Container { Padding = new MarginPadding { @@ -85,7 +86,7 @@ namespace osu.Game.Overlays.Settings AutoSizeAxes = Axes.Y, Children = new Drawable[] { - new OsuSpriteText + header = new OsuSpriteText { Font = OsuFont.GetFont(size: header_size), Text = Header, @@ -134,12 +135,17 @@ namespace osu.Game.Overlays.Settings private void updateContentFade() { - float targetFade = 1; + float contentFade = 1; + float headerFade = 1; if (!isCurrentSection) - targetFade = IsHovered ? 0.6f : 0.25f; + { + contentFade = 0.25f; + headerFade = IsHovered ? 0.5f : 0.25f; + } - content.FadeTo(targetFade, 500, Easing.OutQuint); + header.FadeTo(headerFade, 500, Easing.OutQuint); + FlowContent.FadeTo(contentFade, 500, Easing.OutQuint); } } } From 2d19f37dc6100a605b725e8d1eeb938109c43e06 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 17:40:41 +0900 Subject: [PATCH 516/961] Add missing `new` method in `UserTrackingScrollContainer` for scrolling into view --- osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs index 17506ce0f5..0561051e35 100644 --- a/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs +++ b/osu.Game/Graphics/Containers/UserTrackingScrollContainer.cs @@ -42,6 +42,12 @@ namespace osu.Game.Graphics.Containers base.OnUserScroll(value, animated, distanceDecay); } + public new void ScrollIntoView(Drawable target, bool animated = true) + { + UserScrolling = false; + base.ScrollIntoView(target, animated); + } + public new void ScrollTo(float value, bool animated = true, double? distanceDecay = null) { UserScrolling = false; From 03e6ca5ba930830960bb5541f7b7be6fb2dc0f9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 17:40:56 +0900 Subject: [PATCH 517/961] Adjust scroll behaviour to feel better --- .../Graphics/Containers/SectionsContainer.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 4b368b98ad..d0aa885f3e 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -112,7 +112,7 @@ namespace osu.Game.Graphics.Containers /// /// The percentage of the container to consider the centre-point for deciding the active section (and scrolling to a requested section). /// - private const float scroll_y_centre = 0.2f; + private const float scroll_y_centre = 0.1f; public SectionsContainer() { @@ -147,10 +147,22 @@ namespace osu.Game.Graphics.Containers public void ScrollTo(Drawable target) { + lastKnownScroll = null; + + float fixedHeaderSize = FixedHeader?.BoundingBox.Height ?? 0; + + // implementation similar to ScrollIntoView but a bit more nuanced. + float top = scrollContainer.GetChildPosInContent(target); + + var bottomScrollExtent = scrollContainer.ScrollableExtent - fixedHeaderSize; + + if (top > bottomScrollExtent) + scrollContainer.ScrollToEnd(); + else + scrollContainer.ScrollTo(top - fixedHeaderSize - scrollContainer.DisplayableContent * scroll_y_centre); + if (target is T section) lastClickedSection = section; - - scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(target) - scrollContainer.DisplayableContent * scroll_y_centre - (FixedHeader?.BoundingBox.Height ?? 0)); } public void ScrollToTop() => scrollContainer.ScrollTo(0); From 258ba4674cf210b66e9ca29405b4764c5989d04e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 17:50:49 +0900 Subject: [PATCH 518/961] Fix background overflows --- osu.Game/Screens/BackgroundScreen.cs | 18 +++++++-------- osu.Game/Screens/BackgroundScreenStack.cs | 4 +++- .../Components/RoomBackgroundScreen.cs | 22 +++++++++++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/osu.Game/Screens/BackgroundScreen.cs b/osu.Game/Screens/BackgroundScreen.cs index a6fb94b151..a706934cce 100644 --- a/osu.Game/Screens/BackgroundScreen.cs +++ b/osu.Game/Screens/BackgroundScreen.cs @@ -11,6 +11,9 @@ namespace osu.Game.Screens { public abstract class BackgroundScreen : Screen, IEquatable { + protected const float TRANSITION_LENGTH = 500; + private const float x_movement_amount = 50; + private readonly bool animateOnEnter; public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; @@ -27,9 +30,6 @@ namespace osu.Game.Screens return other?.GetType() == GetType(); } - private const float transition_length = 500; - private const float x_movement_amount = 50; - protected override bool OnKeyDown(KeyDownEvent e) { // we don't want to handle escape key. @@ -55,8 +55,8 @@ namespace osu.Game.Screens this.FadeOut(); this.MoveToX(x_movement_amount); - this.FadeIn(transition_length, Easing.InOutQuart); - this.MoveToX(0, transition_length, Easing.InOutQuart); + this.FadeIn(TRANSITION_LENGTH, Easing.InOutQuart); + this.MoveToX(0, TRANSITION_LENGTH, Easing.InOutQuart); } base.OnEntering(last); @@ -64,7 +64,7 @@ namespace osu.Game.Screens public override void OnSuspending(IScreen next) { - this.MoveToX(-x_movement_amount, transition_length, Easing.InOutQuart); + this.MoveToX(-x_movement_amount, TRANSITION_LENGTH, Easing.InOutQuart); base.OnSuspending(next); } @@ -72,8 +72,8 @@ namespace osu.Game.Screens { if (IsLoaded) { - this.FadeOut(transition_length, Easing.OutExpo); - this.MoveToX(x_movement_amount, transition_length, Easing.OutExpo); + this.FadeOut(TRANSITION_LENGTH, Easing.OutExpo); + this.MoveToX(x_movement_amount, TRANSITION_LENGTH, Easing.OutExpo); } return base.OnExiting(next); @@ -82,7 +82,7 @@ namespace osu.Game.Screens public override void OnResuming(IScreen last) { if (IsLoaded) - this.MoveToX(0, transition_length, Easing.OutExpo); + this.MoveToX(0, TRANSITION_LENGTH, Easing.OutExpo); base.OnResuming(last); } } diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs index 9c0c5da0fb..17894d2474 100644 --- a/osu.Game/Screens/BackgroundScreenStack.cs +++ b/osu.Game/Screens/BackgroundScreenStack.cs @@ -10,10 +10,12 @@ namespace osu.Game.Screens { public class BackgroundScreenStack : ScreenStack { + public const float BACKGROUND_SCALE = 1.06f; + public BackgroundScreenStack() : base(false) { - Scale = new Vector2(1.06f); + Scale = new Vector2(BACKGROUND_SCALE); RelativeSizeAxes = Axes.Both; Anchor = Anchor.Centre; Origin = Anchor.Centre; diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs index efcfa35e19..393cf49bb7 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs @@ -8,6 +8,7 @@ using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Screens; using osu.Game.Online.Rooms; using osuTK; @@ -86,5 +87,26 @@ namespace osu.Game.Screens.OnlinePlay.Components AddInternal(background = newBackground); } + + protected override void Update() + { + base.Update(); + + // This is a static screen, so override the scale set in base.Update(), but also the scale set by the screen stack. + Scale = new Vector2(1f / BackgroundScreenStack.BACKGROUND_SCALE); + } + + public override void OnSuspending(IScreen next) + { + base.OnSuspending(next); + this.MoveToX(0, TRANSITION_LENGTH); + } + + public override bool OnExiting(IScreen next) + { + var result = base.OnExiting(next); + this.MoveToX(0); + return result; + } } } From 591ba8cb099a0ab4d9488fea7877ea4304c6179e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 17:56:35 +0900 Subject: [PATCH 519/961] Ensure the final scroll target is used when checking for whether too far down --- osu.Game/Graphics/Containers/SectionsContainer.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index d0aa885f3e..76492cab55 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -154,12 +154,13 @@ namespace osu.Game.Graphics.Containers // implementation similar to ScrollIntoView but a bit more nuanced. float top = scrollContainer.GetChildPosInContent(target); - var bottomScrollExtent = scrollContainer.ScrollableExtent - fixedHeaderSize; + float bottomScrollExtent = scrollContainer.ScrollableExtent - fixedHeaderSize; + float scrollTarget = top - fixedHeaderSize - scrollContainer.DisplayableContent * scroll_y_centre; - if (top > bottomScrollExtent) + if (scrollTarget > bottomScrollExtent) scrollContainer.ScrollToEnd(); else - scrollContainer.ScrollTo(top - fixedHeaderSize - scrollContainer.DisplayableContent * scroll_y_centre); + scrollContainer.ScrollTo(scrollTarget); if (target is T section) lastClickedSection = section; From c22c6f3a49057544546594d2d4d34c9a255c2f02 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 18:14:12 +0900 Subject: [PATCH 520/961] Initial room background implementation --- ...creen.cs => OnlinePlayBackgroundScreen.cs} | 35 +++++---------- .../Lounge/LoungeBackgroundScreen.cs | 45 +++++++++++++++++++ .../OnlinePlay/Lounge/LoungeSubScreen.cs | 4 +- .../OnlinePlay/Match/RoomBackgroundScreen.cs | 19 ++++++++ .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 +++ 5 files changed, 83 insertions(+), 25 deletions(-) rename osu.Game/Screens/OnlinePlay/Components/{RoomBackgroundScreen.cs => OnlinePlayBackgroundScreen.cs} (74%) create mode 100644 osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs create mode 100644 osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs diff --git a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs similarity index 74% rename from osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs rename to osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs index 393cf49bb7..5077979bf0 100644 --- a/osu.Game/Screens/OnlinePlay/Components/RoomBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs @@ -1,57 +1,47 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable enable - -using System.Linq; using System.Threading; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Game.Online.Rooms; using osuTK; +#nullable enable + namespace osu.Game.Screens.OnlinePlay.Components { - public class RoomBackgroundScreen : BackgroundScreen + public abstract class OnlinePlayBackgroundScreen : BackgroundScreen { private CancellationTokenSource? cancellationSource; private PlaylistItemBackground? background; - private readonly BindableList playlist = new BindableList(); - - public RoomBackgroundScreen() + protected OnlinePlayBackgroundScreen() : base(false) { - playlist.BindCollectionChanged((_, __) => updateBackground()); } [BackgroundDependencyLoader] private void load() { - switchBackground(new PlaylistItemBackground(null)); + switchBackground(new PlaylistItemBackground(playlistItem)); } - private Room? room; + private PlaylistItem? playlistItem; - public Room? Room + protected PlaylistItem? PlaylistItem { - get => room; + get => playlistItem; set { - if (room == value) + if (playlistItem == value) return; - if (room != null) - playlist.UnbindFrom(room.Playlist); + playlistItem = value; - room = value; - - if (room != null) - playlist.BindTo(room.Playlist); - else - playlist.Clear(); + if (LoadState > LoadState.Ready) + updateBackground(); } } @@ -59,7 +49,6 @@ namespace osu.Game.Screens.OnlinePlay.Components { Schedule(() => { - var playlistItem = playlist.FirstOrDefault(); var beatmap = playlistItem?.Beatmap.Value; if (background?.BeatmapInfo?.BeatmapSet?.OnlineInfo?.Covers?.Cover == beatmap?.BeatmapSet?.OnlineInfo?.Covers?.Cover) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs new file mode 100644 index 0000000000..7d38e220d3 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.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. + +#nullable enable + +using System.Linq; +using osu.Framework.Bindables; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; +using PlaylistItem = osu.Game.Online.Rooms.PlaylistItem; + +namespace osu.Game.Screens.OnlinePlay.Lounge +{ + public class LoungeBackgroundScreen : OnlinePlayBackgroundScreen + { + private readonly BindableList playlist = new BindableList(); + + public LoungeBackgroundScreen() + { + playlist.BindCollectionChanged((_, __) => PlaylistItem = playlist.FirstOrDefault()); + } + + private Room? selectedRoom; + + public Room? SelectedRoom + { + get => selectedRoom; + set + { + if (selectedRoom == value) + return; + + if (selectedRoom != null) + playlist.UnbindFrom(selectedRoom.Playlist); + + selectedRoom = value; + + if (selectedRoom != null) + playlist.BindTo(selectedRoom.Playlist); + else + playlist.Clear(); + } + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 34beba923f..90e5a62d7e 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; - protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen(); + protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen(); protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -169,7 +169,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge if (drawable != null) scrollContainer.ScrollIntoView(drawable); - ApplyToBackground(b => ((RoomBackgroundScreen)b).Room = val.NewValue); + ApplyToBackground(b => ((LoungeBackgroundScreen)b).SelectedRoom = val.NewValue); }); } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs new file mode 100644 index 0000000000..cacc3864c2 --- /dev/null +++ b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Game.Online.Rooms; +using osu.Game.Screens.OnlinePlay.Components; + +namespace osu.Game.Screens.OnlinePlay.Match +{ + public class RoomBackgroundScreen : OnlinePlayBackgroundScreen + { + public readonly Bindable SelectedItem = new Bindable(); + + public RoomBackgroundScreen() + { + SelectedItem.BindValueChanged(item => PlaylistItem = item.NewValue); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index d6a23ff708..8097e91c2e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -29,6 +29,11 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached(typeof(IBindable))] protected readonly Bindable SelectedItem = new Bindable(); + protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen + { + SelectedItem = { BindTarget = SelectedItem } + }; + public override bool DisallowExternalBeatmapRulesetChanges => true; /// From d304e283e4a24506923f48097b84494086ef38d6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 18:14:59 +0900 Subject: [PATCH 521/961] Don't deselect online room when joined --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 4e106b844c..70342680e2 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -172,8 +172,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge sampleJoin?.Play(); lounge?.Join(Room, null); - - return base.OnClick(e); + return true; } public class PasswordEntryPopover : OsuPopover From cbee379f62cdc49b8227067fd952f5bd57bbe172 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 20 Aug 2021 12:30:49 +0300 Subject: [PATCH 522/961] Test scrolled to section top is visible --- .../UserInterface/TestSceneSectionsContainer.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs index 5c2e6e457d..2312c57af2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneSectionsContainer.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Shapes; +using osu.Framework.Testing; using osu.Game.Graphics.Containers; using osuTK.Graphics; @@ -61,10 +62,12 @@ namespace osu.Game.Tests.Visual.UserInterface )); AddStep("scroll up", () => triggerUserScroll(1)); AddStep("scroll down", () => triggerUserScroll(-1)); + AddStep("scroll up a bit", () => triggerUserScroll(0.1f)); + AddStep("scroll down a bit", () => triggerUserScroll(-0.1f)); } [Test] - public void TestCorrectSectionSelected() + public void TestCorrectSelectionAndVisibleTop() { const int sections_count = 11; float[] alternating = { 0.07f, 0.33f, 0.16f, 0.33f }; @@ -79,6 +82,12 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep($"scroll to section {scrollIndex + 1}", () => container.ScrollTo(container.Children[scrollIndex])); AddUntilStep("correct section selected", () => container.SelectedSection.Value == container.Children[scrollIndex]); + AddUntilStep("section top is visible", () => + { + float scrollPosition = container.ChildrenOfType().First().Current; + float sectionTop = container.Children[scrollIndex].BoundingBox.Top; + return scrollPosition < sectionTop; + }); } for (int i = 1; i < sections_count; i++) From 77149044a5954278d9deef2b014c5fe267033915 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 19:33:47 +0900 Subject: [PATCH 523/961] Allow intro screen to retrieve beatmap even if rulesets is not loaded --- osu.Game/Beatmaps/BeatmapManager.cs | 36 +++++++++++++++++++++++++++- osu.Game/Beatmaps/BeatmapStore.cs | 7 ++++++ osu.Game/Screens/Menu/IntroScreen.cs | 3 ++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 4a78ceb299..241649062e 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -365,6 +365,10 @@ namespace osu.Game.Beatmaps queryable = beatmaps.BeatmapSetsOverview; break; + case IncludedDetails.AllButRuleset: + queryable = beatmaps.BeatmapSetsWithoutRuleset; + break; + case IncludedDetails.AllButFiles: queryable = beatmaps.BeatmapSetsWithoutFiles; break; @@ -384,8 +388,33 @@ namespace osu.Game.Beatmaps /// Perform a lookup query on available s. /// /// The query. + /// The level of detail to include in the returned objects. /// Results from the provided query. - public IEnumerable QueryBeatmapSets(Expression> query) => beatmaps.ConsumableItems.AsNoTracking().Where(query); + public IEnumerable QueryBeatmapSets(Expression> query, IncludedDetails includes = IncludedDetails.All) + { + IQueryable queryable; + + switch (includes) + { + case IncludedDetails.Minimal: + queryable = beatmaps.BeatmapSetsOverview; + break; + + case IncludedDetails.AllButRuleset: + queryable = beatmaps.BeatmapSetsWithoutRuleset; + break; + + case IncludedDetails.AllButFiles: + queryable = beatmaps.BeatmapSetsWithoutFiles; + break; + + default: + queryable = beatmaps.ConsumableItems; + break; + } + + return queryable.AsNoTracking().Where(query); + } /// /// Perform a lookup query on available s. @@ -554,6 +583,11 @@ namespace osu.Game.Beatmaps /// AllButFiles, + /// + /// Include everything except ruleset. Used for cases where we aren't sure the ruleset is present but still want to consume the beatmap. + /// + AllButRuleset, + /// /// Include everything. /// diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 642bafd2ac..e3214b7c03 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -92,6 +92,13 @@ namespace osu.Game.Beatmaps .Include(s => s.Beatmaps) .AsNoTracking(); + public IQueryable BeatmapSetsWithoutRuleset => ContextFactory.Get().BeatmapSetInfo + .Include(s => s.Metadata) + .Include(s => s.Files).ThenInclude(f => f.FileInfo) + .Include(s => s.Beatmaps).ThenInclude(b => b.BaseDifficulty) + .Include(s => s.Beatmaps).ThenInclude(b => b.Metadata) + .AsNoTracking(); + public IQueryable BeatmapSetsWithoutFiles => ContextFactory.Get().BeatmapSetInfo .Include(s => s.Metadata) .Include(s => s.Beatmaps).ThenInclude(s => s.Ruleset) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 71f3b60026..07a94fb97e 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.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.Audio; using osu.Framework.Audio.Sample; @@ -109,7 +110,7 @@ namespace osu.Game.Screens.Menu bool loadThemedIntro() { - setInfo = beatmaps.QueryBeatmapSet(b => b.Hash == BeatmapHash); + setInfo = beatmaps.QueryBeatmapSets(b => b.Hash == BeatmapHash, IncludedDetails.AllButRuleset).FirstOrDefault(); if (setInfo == null) return false; From b9ff94485db48af93f12ea0fbd879737d76a7bd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 19:45:52 +0900 Subject: [PATCH 524/961] Revert usage of `OsuGameTestScene` for `TestSceneOsuGame` Turns out we likely don't want this, as it means the testing user (using a visual test browser) will not have access to their beatmaps. Can revisit at a future date if the temporary files are still an issue. --- .../TestSceneOsuGame.cs | 23 +++++++++++- .../TestSceneOsuGame.cs | 23 +++++++++++- .../TestSceneOsuGame.cs | 23 +++++++++++- .../TestSceneOsuGame.cs | 23 +++++++++++- .../Visual/Navigation/TestSceneOsuGame.cs | 37 ++++++++++++++++++- 5 files changed, 123 insertions(+), 6 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs index fb63f69f72..9c512a01ea 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/TestSceneOsuGame.cs @@ -1,11 +1,32 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; using osu.Game.Tests.Visual; +using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyFreeform.Tests { - public class TestSceneOsuGame : OsuGameTestScene + public class TestSceneOsuGame : OsuTestScene { + [BackgroundDependencyLoader] + private void load(GameHost host, OsuGameBase gameBase) + { + OsuGame game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + } } } diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index a99a400afa..270d906b01 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -1,11 +1,32 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; using osu.Game.Tests.Visual; +using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuGameTestScene + public class TestSceneOsuGame : OsuTestScene { + [BackgroundDependencyLoader] + private void load(GameHost host, OsuGameBase gameBase) + { + OsuGame game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + } } } diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs index debdc14b57..aed6abb6bf 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/TestSceneOsuGame.cs @@ -1,11 +1,32 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; using osu.Game.Tests.Visual; +using osuTK.Graphics; namespace osu.Game.Rulesets.EmptyScrolling.Tests { - public class TestSceneOsuGame : OsuGameTestScene + public class TestSceneOsuGame : OsuTestScene { + [BackgroundDependencyLoader] + private void load(GameHost host, OsuGameBase gameBase) + { + OsuGame game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + } } } diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs index a99a400afa..270d906b01 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/TestSceneOsuGame.cs @@ -1,11 +1,32 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Platform; using osu.Game.Tests.Visual; +using osuTK.Graphics; namespace osu.Game.Rulesets.Pippidon.Tests { - public class TestSceneOsuGame : OsuGameTestScene + public class TestSceneOsuGame : OsuTestScene { + [BackgroundDependencyLoader] + private void load(GameHost host, OsuGameBase gameBase) + { + OsuGame game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + } } } diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index d3f1a852d1..48e68b03fb 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -6,7 +6,11 @@ using System.Collections.Generic; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Textures; +using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -24,11 +28,12 @@ using osu.Game.Scoring; using osu.Game.Screens.Menu; using osu.Game.Skinning; using osu.Game.Utils; +using osuTK.Graphics; namespace osu.Game.Tests.Visual.Navigation { [TestFixture] - public class TestSceneOsuGame : OsuGameTestScene + public class TestSceneOsuGame : OsuTestScene { private IReadOnlyList requiredGameDependencies => new[] { @@ -79,9 +84,37 @@ namespace osu.Game.Tests.Visual.Navigation typeof(PreviewTrackManager), }; + private OsuGame game; + [Resolved] private OsuGameBase gameBase { get; set; } + [Resolved] + private GameHost host { get; set; } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create game", () => + { + game = new OsuGame(); + game.SetHost(host); + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + game + }; + }); + + AddUntilStep("wait for load", () => game.IsLoaded); + } + + [Test] public void TestNullRulesetHandled() { @@ -117,7 +150,7 @@ namespace osu.Game.Tests.Visual.Navigation { foreach (var type in requiredGameDependencies) { - if (Game.Dependencies.Get(type) == null) + if (game.Dependencies.Get(type) == null) throw new InvalidOperationException($"{type} has not been cached"); } From b190020c4b78d0dab21a33d22c9f7637a3124fbb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:02:25 +0900 Subject: [PATCH 525/961] Block lounge background screen from exiting --- .../Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs index 7d38e220d3..743fb1fbbf 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs @@ -5,6 +5,7 @@ using System.Linq; using osu.Framework.Bindables; +using osu.Framework.Screens; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using PlaylistItem = osu.Game.Online.Rooms.PlaylistItem; @@ -41,5 +42,11 @@ namespace osu.Game.Screens.OnlinePlay.Lounge playlist.Clear(); } } + + public override bool OnExiting(IScreen next) + { + // This screen never exits. + return true; + } } } From 9458cd5a31476d3d1955fc5d595080f91f3a7e0c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:07:51 +0900 Subject: [PATCH 526/961] Make DrawableMatchRoom background load instantly --- .../OnlinePlay/Match/DrawableMatchRoom.cs | 13 +++++++- .../OnlinePlay/Match/RoomBackgroundSprite.cs | 33 ------------------- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 3 +- 3 files changed, 14 insertions(+), 35 deletions(-) delete mode 100644 osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs diff --git a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs index 0924773338..e83403850f 100644 --- a/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Match/DrawableMatchRoom.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Game.Beatmaps.Drawables; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge.Components; @@ -17,6 +18,7 @@ namespace osu.Game.Screens.OnlinePlay.Match { public class DrawableMatchRoom : DrawableRoom { + public readonly IBindable SelectedItem = new Bindable(); public Action OnEdit; [Resolved] @@ -28,6 +30,8 @@ namespace osu.Game.Screens.OnlinePlay.Match [CanBeNull] private Drawable editButton; + private BackgroundSprite background; + public DrawableMatchRoom(Room room, bool allowEdit = true) : base(room) { @@ -57,8 +61,15 @@ namespace osu.Game.Screens.OnlinePlay.Match if (editButton != null) host.BindValueChanged(h => editButton.Alpha = h.NewValue?.Equals(api.LocalUser.Value) == true ? 1 : 0, true); + + SelectedItem.BindValueChanged(item => background.Beatmap.Value = item.NewValue?.Beatmap.Value, true); } - protected override Drawable CreateBackground() => new RoomBackgroundSprite(); + protected override Drawable CreateBackground() => background = new BackgroundSprite(); + + private class BackgroundSprite : UpdateableBeatmapBackgroundSprite + { + protected override double LoadDelay => 0; + } } } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs deleted file mode 100644 index 97262dd229..0000000000 --- a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundSprite.cs +++ /dev/null @@ -1,33 +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.Game.Beatmaps.Drawables; - -namespace osu.Game.Screens.OnlinePlay.Match -{ - public class RoomBackgroundSprite : RoomSubScreenComposite - { - protected readonly BeatmapSetCoverType BeatmapSetCoverType; - private UpdateableBeatmapBackgroundSprite sprite; - - public RoomBackgroundSprite(BeatmapSetCoverType beatmapSetCoverType = BeatmapSetCoverType.Cover) - { - BeatmapSetCoverType = beatmapSetCoverType; - } - - [BackgroundDependencyLoader] - private void load() - { - InternalChild = sprite = new UpdateableBeatmapBackgroundSprite(BeatmapSetCoverType) { RelativeSizeAxes = Axes.Both }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - SelectedItem.BindValueChanged(item => sprite.Beatmap.Value = item.NewValue?.Beatmap.Value, true); - } - } -} diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 8097e91c2e..214540fe10 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -139,7 +139,8 @@ namespace osu.Game.Screens.OnlinePlay.Match { new DrawableMatchRoom(Room, allowEdit) { - OnEdit = () => settingsOverlay.Show() + OnEdit = () => settingsOverlay.Show(), + SelectedItem = { BindTarget = SelectedItem } } }, null, From b1a732b9b7928d73d76db540e2feffece095aae2 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:28:48 +0900 Subject: [PATCH 527/961] Remove selectedRoom from OnlinePlayScreen --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 4 +--- osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 11 ----------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 90e5a62d7e..e2a4f3dfdf 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -49,9 +49,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected ListingPollingComponent ListingPollingComponent { get; private set; } - [Resolved] - private Bindable selectedRoom { get; set; } - [Resolved] private MusicController music { get; set; } @@ -68,6 +65,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private LeasedBindable selectionLease; private readonly Bindable filter = new Bindable(new FilterCriteria()); + private readonly Bindable selectedRoom = new Bindable(); private readonly IBindable operationInProgress = new Bindable(); private readonly IBindable isIdle = new BindableBool(); private LoadingLayer loadingLayer; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index 76815172e5..fc20b21b60 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -10,7 +10,6 @@ using osu.Framework.Logging; using osu.Framework.Screens; using osu.Game.Graphics.Containers; using osu.Game.Online.API; -using osu.Game.Online.Rooms; using osu.Game.Overlays; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Components; @@ -38,9 +37,6 @@ namespace osu.Game.Screens.OnlinePlay [Cached(Type = typeof(IRoomManager))] protected RoomManager RoomManager { get; private set; } - [Cached] - private readonly Bindable selectedRoom = new Bindable(); - [Cached] private readonly OngoingOperationTracker ongoingOperationTracker = new OngoingOperationTracker(); @@ -106,13 +102,6 @@ namespace osu.Game.Screens.OnlinePlay apiState.BindValueChanged(onlineStateChanged, true); } - protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) - { - var dependencies = new CachedModelDependencyContainer(base.CreateChildDependencies(parent)); - dependencies.Model.BindTo(selectedRoom); - return dependencies; - } - private void forcefullyExit() { // This is temporary since we don't currently have a way to force screens to be exited From 5c8ca32ea4b94387d082b8a994d261cb2a62c717 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:33:21 +0900 Subject: [PATCH 528/961] Simplify lounge implementation --- .../Lounge/LoungeBackgroundScreen.cs | 27 +++++++------------ .../OnlinePlay/Lounge/LoungeSubScreen.cs | 4 +-- .../Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 +--- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs index 743fb1fbbf..6c00ca2e81 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeBackgroundScreen.cs @@ -14,33 +14,24 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public class LoungeBackgroundScreen : OnlinePlayBackgroundScreen { + public readonly Bindable SelectedRoom = new Bindable(); private readonly BindableList playlist = new BindableList(); public LoungeBackgroundScreen() { + SelectedRoom.BindValueChanged(onSelectedRoomChanged); playlist.BindCollectionChanged((_, __) => PlaylistItem = playlist.FirstOrDefault()); } - private Room? selectedRoom; - - public Room? SelectedRoom + private void onSelectedRoomChanged(ValueChangedEvent room) { - get => selectedRoom; - set - { - if (selectedRoom == value) - return; + if (room.OldValue != null) + playlist.UnbindFrom(room.OldValue.Playlist); - if (selectedRoom != null) - playlist.UnbindFrom(selectedRoom.Playlist); - - selectedRoom = value; - - if (selectedRoom != null) - playlist.BindTo(selectedRoom.Playlist); - else - playlist.Clear(); - } + if (room.NewValue != null) + playlist.BindTo(room.NewValue.Playlist); + else + playlist.Clear(); } public override bool OnExiting(IScreen next) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index e2a4f3dfdf..034deba54a 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -36,7 +36,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; - protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen(); + protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen { SelectedRoom = { BindTarget = selectedRoom } }; protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -166,8 +166,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge var drawable = roomsContainer.Rooms.FirstOrDefault(r => r.Room == val.NewValue); if (drawable != null) scrollContainer.ScrollIntoView(drawable); - - ApplyToBackground(b => ((LoungeBackgroundScreen)b).SelectedRoom = val.NewValue); }); } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 214540fe10..36cd8c4df3 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -29,10 +29,7 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached(typeof(IBindable))] protected readonly Bindable SelectedItem = new Bindable(); - protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen - { - SelectedItem = { BindTarget = SelectedItem } - }; + protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen { SelectedItem = { BindTarget = SelectedItem } }; public override bool DisallowExternalBeatmapRulesetChanges => true; From 5192ee3b5713efe0e167d789d59b897cf894ed99 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:40:35 +0900 Subject: [PATCH 529/961] Fix initial display in room background --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 5 ++++- osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs | 3 ++- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 034deba54a..ee51b37849 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -36,7 +36,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { public override string Title => "Lounge"; - protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen { SelectedRoom = { BindTarget = selectedRoom } }; + protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen + { + SelectedRoom = { BindTarget = selectedRoom } + }; protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs index cacc3864c2..2e5f25370f 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomBackgroundScreen.cs @@ -11,8 +11,9 @@ namespace osu.Game.Screens.OnlinePlay.Match { public readonly Bindable SelectedItem = new Bindable(); - public RoomBackgroundScreen() + public RoomBackgroundScreen(PlaylistItem initialPlaylistItem) { + PlaylistItem = initialPlaylistItem; SelectedItem.BindValueChanged(item => PlaylistItem = item.NewValue); } } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 36cd8c4df3..8ab3f77888 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -29,7 +29,10 @@ namespace osu.Game.Screens.OnlinePlay.Match [Cached(typeof(IBindable))] protected readonly Bindable SelectedItem = new Bindable(); - protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen { SelectedItem = { BindTarget = SelectedItem } }; + protected override BackgroundScreen CreateBackground() => new RoomBackgroundScreen(Room.Playlist.FirstOrDefault()) + { + SelectedItem = { BindTarget = SelectedItem } + }; public override bool DisallowExternalBeatmapRulesetChanges => true; From f85d3665d82f1edc9444f6bddd5fa5ffa8c36482 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 20 Aug 2021 21:45:24 +0900 Subject: [PATCH 530/961] Cleanups --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 1 - osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 2 +- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 3 --- osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs | 3 --- 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index ee51b37849..7e898db584 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -235,7 +235,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge public override void OnEntering(IScreen last) { base.OnEntering(last); - onReturning(); } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index 8ab3f77888..c05022a903 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -426,7 +426,7 @@ namespace osu.Game.Screens.OnlinePlay.Match /// /// Creates the room settings overlay. /// - /// + /// The room to change the settings of. protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); private class UserModSelectOverlay : LocalPlayerModSelectOverlay diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 1cb3ce0b12..06e60903aa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -78,9 +78,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer if (!connected.NewValue) handleRoomLost(); }, true); - - // if (client.Room == null) - // handleRoomLost(); } protected override Drawable CreateMainContent() => new GridContainer diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs index 371824577e..3411c4afb1 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreen.cs @@ -36,9 +36,7 @@ namespace osu.Game.Screens.OnlinePlay public override bool OnExiting(IScreen next) { base.OnExiting(next); - this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); - return false; } @@ -51,7 +49,6 @@ namespace osu.Game.Screens.OnlinePlay public override void OnSuspending(IScreen next) { base.OnSuspending(next); - this.FadeOut(DISAPPEAR_DURATION, Easing.OutQuint); } From 5e234fb7468942ef724c616f893cf7a50ba0853b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 22:07:13 +0900 Subject: [PATCH 531/961] Add try catch to avoid test failures on windows --- osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs index c9f5774735..5e14af5c27 100644 --- a/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs +++ b/osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs @@ -313,9 +313,13 @@ namespace osu.Game.Tests.NonVisual { base.Dispose(isDisposing); - // the storage may have changed from the initial location. - // this handles cleanup of the initial location. - InitialStorage.DeleteDirectory(string.Empty); + try + { + // the storage may have changed from the initial location. + // this handles cleanup of the initial location. + InitialStorage.DeleteDirectory(string.Empty); + } + catch { } } } } From e13b516f31e28c69c74a5bcf83c04d09787291d5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 22:26:36 +0900 Subject: [PATCH 532/961] Fix excess blank lines --- osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index 48e68b03fb..b8232837b5 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -114,7 +114,6 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("wait for load", () => game.IsLoaded); } - [Test] public void TestNullRulesetHandled() { From d3dba296d672afa4d5c4d7c97154fe68117935a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 20 Aug 2021 23:47:35 +0900 Subject: [PATCH 533/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f74b5d410b..8fd761691c 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index e4838dc95a..0abd9adf77 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 5338ad5deb..d03985a0c2 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 8745fe9e34f38132487356b0ea4fff71dab3b167 Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 20 Aug 2021 22:32:04 +0300 Subject: [PATCH 534/961] Change editor timestamp regex to not match non-editor ones --- osu.Game/Online/Chat/MessageFormatter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index ae9199c428..d72104816f 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -43,7 +43,7 @@ namespace osu.Game.Online.Chat RegexOptions.IgnoreCase); // 00:00:000 (1,2,3) - test - private static readonly Regex time_regex = new Regex(@"\d\d:\d\d:\d\d\d? [^-]*"); + private static readonly Regex time_regex = new Regex(@"\d\d:\d\d:\d\d\d? \((\d,?)+\)"); // #osu private static readonly Regex channel_regex = new Regex(@"(#[a-zA-Z]+[a-zA-Z0-9]+)"); From 058d2d2a49eaa4eb929b59c900f0b11b26f2d73a Mon Sep 17 00:00:00 2001 From: Endrik Tombak Date: Fri, 20 Aug 2021 23:01:06 +0300 Subject: [PATCH 535/961] Use nekodex's regex from osu-web --- osu.Game/Online/Chat/MessageFormatter.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs index d72104816f..0e4ea694aa 100644 --- a/osu.Game/Online/Chat/MessageFormatter.cs +++ b/osu.Game/Online/Chat/MessageFormatter.cs @@ -43,7 +43,8 @@ namespace osu.Game.Online.Chat RegexOptions.IgnoreCase); // 00:00:000 (1,2,3) - test - private static readonly Regex time_regex = new Regex(@"\d\d:\d\d:\d\d\d? \((\d,?)+\)"); + // regex from https://github.com/ppy/osu-web/blob/651a9bac2b60d031edd7e33b8073a469bf11edaa/resources/assets/coffee/_classes/beatmap-discussion-helper.coffee#L10 + private static readonly Regex time_regex = new Regex(@"\b(((\d{2,}):([0-5]\d)[:.](\d{3}))(\s\((?:\d+[,|])*\d+\))?)"); // #osu private static readonly Regex channel_regex = new Regex(@"(#[a-zA-Z]+[a-zA-Z0-9]+)"); From 20f193c1c2eb6f85ab522884946d97423dbf0f60 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Aug 2021 04:15:54 +0300 Subject: [PATCH 536/961] Fix screen offsetting not handling scaled game instances By using `Content` instead, now the logic will get the X of the settings overlay at the `Content` space, which can be scaled in the `ScalingMode.Everything` mode. And in the case of `ScalingMode.ExcludeOverlays`, a subcontainer somewhere inside `Content` that's holding the screen stack would be scaled, but `Content` won't be affected which is what we want in that case. --- osu.Game/OsuGame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 0db63df69b..b9a649fda2 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1019,9 +1019,9 @@ namespace osu.Game var horizontalOffset = 0f; if (Settings.IsLoaded && Settings.IsPresent) - horizontalOffset += ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO; + horizontalOffset += Content.ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO; if (Notifications.IsLoaded && Notifications.IsPresent) - horizontalOffset += (ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - DrawWidth) * SIDE_OVERLAY_OFFSET_RATIO; + horizontalOffset += (Content.ToLocalSpace(Notifications.ScreenSpaceDrawQuad.TopLeft).X - Content.DrawWidth) * SIDE_OVERLAY_OFFSET_RATIO; ScreenOffsetContainer.X = horizontalOffset; From 318f830cd22152eaf712cbe5f5abd7458f8c4463 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Aug 2021 04:18:03 +0300 Subject: [PATCH 537/961] Expand test coverage for different scaling modes Intentionally not using `[Values]` as the scale modes can be applied to the running game instance directly, rather than recreating it all over again. The same could be said for the notification overlay but not sure, seems like something that should be considered at an `OsuGameTestScene` level instead (whether the same game instance can be reused for further testing). --- .../Visual/Menus/TestSceneSideOverlays.cs | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs index 5230e026bc..e34ec6c46a 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneSideOverlays.cs @@ -1,8 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Configuration; using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Menus @@ -21,21 +25,48 @@ namespace osu.Game.Tests.Visual.Menus [Test] public void TestScreenOffsettingOnSettingsOverlay() { - AddStep("open settings", () => Game.Settings.Show()); - AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO); + foreach (var scalingMode in Enum.GetValues(typeof(ScalingMode)).Cast()) + { + AddStep($"set scaling mode to {scalingMode}", () => + { + Game.LocalConfig.SetValue(OsuSetting.Scaling, scalingMode); - AddStep("hide settings", () => Game.Settings.Hide()); - AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + if (scalingMode != ScalingMode.Off) + { + Game.LocalConfig.SetValue(OsuSetting.ScalingSizeX, 0.5f); + Game.LocalConfig.SetValue(OsuSetting.ScalingSizeY, 0.5f); + } + }); + + AddStep("open settings", () => Game.Settings.Show()); + AddUntilStep("right screen offset applied", () => Precision.AlmostEquals(Game.ScreenOffsetContainer.X, SettingsPanel.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO)); + + AddStep("hide settings", () => Game.Settings.Hide()); + AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + } } [Test] public void TestScreenOffsettingOnNotificationOverlay() { - AddStep("open notifications", () => Game.Notifications.Show()); - AddUntilStep("right screen offset applied", () => Game.ScreenOffsetContainer.X == -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO); + foreach (var scalingMode in Enum.GetValues(typeof(ScalingMode)).Cast()) + { + if (scalingMode != ScalingMode.Off) + { + AddStep($"set scaling mode to {scalingMode}", () => + { + Game.LocalConfig.SetValue(OsuSetting.Scaling, scalingMode); + Game.LocalConfig.SetValue(OsuSetting.ScalingSizeX, 0.5f); + Game.LocalConfig.SetValue(OsuSetting.ScalingSizeY, 0.5f); + }); + } - AddStep("hide notifications", () => Game.Notifications.Hide()); - AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + AddStep("open notifications", () => Game.Notifications.Show()); + AddUntilStep("right screen offset applied", () => Precision.AlmostEquals(Game.ScreenOffsetContainer.X, -NotificationOverlay.WIDTH * TestOsuGame.SIDE_OVERLAY_OFFSET_RATIO)); + + AddStep("hide notifications", () => Game.Notifications.Hide()); + AddUntilStep("screen offset removed", () => Game.ScreenOffsetContainer.X == 0f); + } } } } From 36352d1de4338014c6a154ebef4157888bd9ba54 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 Aug 2021 14:34:35 +0900 Subject: [PATCH 538/961] Improve highlighted chat username shadow effect --- osu.Game/Overlays/Chat/ChatLine.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs index 01cfe9a55b..6f4f568eb2 100644 --- a/osu.Game/Overlays/Chat/ChatLine.cs +++ b/osu.Game/Overlays/Chat/ChatLine.cs @@ -110,15 +110,15 @@ namespace osu.Game.Overlays.Chat EdgeEffect = new EdgeEffectParameters { Roundness = 1, - Offset = new Vector2(0, 3), - Radius = 3, + Radius = 1, Colour = Color4.Black.Opacity(0.3f), + Offset = new Vector2(0, 1), Type = EdgeEffectType.Shadow, }, Child = new Container { AutoSizeAxes = Axes.Both, - Y = 3, + Y = 0, Masking = true, CornerRadius = 4, Children = new Drawable[] From 15d443f6b7e8e00142ec5757a8973baaf887415a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 Aug 2021 14:44:54 +0900 Subject: [PATCH 539/961] Use the UI mouse cursor when hovering gameplay chat in an interactive state --- osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index e2f135d436..9fe41842f3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Bindings; +using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -38,6 +39,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Textbox.FocusLost = () => expandedFromTextboxFocus.Value = false; } + protected override bool OnHover(HoverEvent e) => true; // use UI mouse cursor. + protected override void LoadComplete() { base.LoadComplete(); From ae47c5cdb3396533d324a76bee5a917e98ec9099 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 21 Aug 2021 15:08:42 +0900 Subject: [PATCH 540/961] Fix bottom area of a settings section not being clickable --- osu.Game/Overlays/Settings/SettingsSection.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsSection.cs b/osu.Game/Overlays/Settings/SettingsSection.cs index 6f167bf059..2a6f3f5ed7 100644 --- a/osu.Game/Overlays/Settings/SettingsSection.cs +++ b/osu.Game/Overlays/Settings/SettingsSection.cs @@ -47,7 +47,6 @@ namespace osu.Game.Overlays.Settings protected SettingsSection() { - Margin = new MarginPadding { Top = margin }; AutoSizeAxes = Axes.Y; RelativeSizeAxes = Axes.X; @@ -80,7 +79,7 @@ namespace osu.Game.Overlays.Settings Padding = new MarginPadding { Top = margin + border_size, - Bottom = 10, + Bottom = margin + 10, }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, From 1729d43cecba9ca9d33203e5f09713693fd4473b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Aug 2021 15:18:03 +0300 Subject: [PATCH 541/961] Add explanatory comment --- osu.Game/OsuGame.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b9a649fda2..b827b687a5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1018,6 +1018,8 @@ namespace osu.Game var horizontalOffset = 0f; + // Calculate the horizontal offset using Content, as it gets nested inside a ScalingMode.Everything container + // which should apply to overlays, but not get affected by modes like ScalingMode.ExcludeOverlays which shouldn't. if (Settings.IsLoaded && Settings.IsPresent) horizontalOffset += Content.ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO; if (Notifications.IsLoaded && Notifications.IsPresent) From 9a6ff2995103596aa944aed5b746805619f9385e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 21 Aug 2021 15:39:57 +0300 Subject: [PATCH 542/961] Reword comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/OsuGame.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b827b687a5..4d952c39c6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -1018,8 +1018,9 @@ namespace osu.Game var horizontalOffset = 0f; - // Calculate the horizontal offset using Content, as it gets nested inside a ScalingMode.Everything container - // which should apply to overlays, but not get affected by modes like ScalingMode.ExcludeOverlays which shouldn't. + // Content.ToLocalSpace() is used instead of this.ToLocalSpace() to correctly calculate the offset with scaling modes active. + // Content is a child of a scaling container with ScalingMode.Everything set, while the game itself is never scaled. + // this avoids a visible jump in the positioning of the screen offset container. if (Settings.IsLoaded && Settings.IsPresent) horizontalOffset += Content.ToLocalSpace(Settings.ScreenSpaceDrawQuad.TopRight).X * SIDE_OVERLAY_OFFSET_RATIO; if (Notifications.IsLoaded && Notifications.IsPresent) From 479401e533682635868cfcedbcb2c7b15179103f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Aug 2021 15:11:08 +0200 Subject: [PATCH 543/961] Add option to set own computation function in test --- .../Beatmaps/TestSceneBeatmapDifficultyCache.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index da457c9e8f..7bbe647302 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -58,6 +58,12 @@ namespace osu.Game.Tests.Beatmaps { OsuModDoubleTime dt = null; + AddStep("set computation function", () => difficultyCache.ComputeDifficulty = lookup => + { + var modRateAdjust = (ModRateAdjust)lookup.OrderedMods.SingleOrDefault(mod => mod is ModRateAdjust); + return new StarDifficulty(BASE_STARS + modRateAdjust?.SpeedChange.Value ?? 0, 0); + }); + AddStep("change selected mod to DT", () => SelectedMods.Value = new[] { dt = new OsuModDoubleTime { SpeedChange = { Value = 1.5 } } }); AddUntilStep($"star difficulty -> {BASE_STARS + 1.5}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.5); @@ -133,13 +139,11 @@ namespace osu.Game.Tests.Beatmaps private class TestBeatmapDifficultyCache : BeatmapDifficultyCache { + public Func ComputeDifficulty { get; set; } + protected override Task ComputeValueAsync(DifficultyCacheLookup lookup, CancellationToken token = default) { - var rateAdjust = lookup.OrderedMods.OfType().SingleOrDefault(); - if (rateAdjust != null) - return Task.FromResult(new StarDifficulty(BASE_STARS + rateAdjust.SpeedChange.Value, 0)); - - return Task.FromResult(new StarDifficulty(BASE_STARS, 0)); + return Task.FromResult(ComputeDifficulty?.Invoke(lookup) ?? new StarDifficulty(BASE_STARS, 0)); } } } From f642546d6a385be54181138ce868a3df80d28950 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Aug 2021 15:15:13 +0200 Subject: [PATCH 544/961] Add failing test case --- .../TestSceneBeatmapDifficultyCache.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index 7bbe647302..2b4dc48fe0 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -74,6 +74,29 @@ namespace osu.Game.Tests.Beatmaps AddUntilStep($"star difficulty -> {BASE_STARS + 1.75}", () => starDifficultyBindable.Value?.Stars == BASE_STARS + 1.75); } + [Test] + public void TestStarDifficultyAdjustHashCodeConflict() + { + OsuModDifficultyAdjust difficultyAdjust = null; + + AddStep("set computation function", () => difficultyCache.ComputeDifficulty = lookup => + { + var modDifficultyAdjust = (ModDifficultyAdjust)lookup.OrderedMods.SingleOrDefault(mod => mod is ModDifficultyAdjust); + return new StarDifficulty(BASE_STARS * (modDifficultyAdjust?.OverallDifficulty.Value ?? 1), 0); + }); + + AddStep("change selected mod to DA", () => SelectedMods.Value = new[] { difficultyAdjust = new OsuModDifficultyAdjust() }); + AddUntilStep($"star difficulty -> {BASE_STARS}", () => starDifficultyBindable.Value?.Stars == BASE_STARS); + + AddStep("change DA difficulty to 0.5", () => difficultyAdjust.OverallDifficulty.Value = 0.5f); + AddUntilStep($"star difficulty -> {BASE_STARS * 0.5f}", () => starDifficultyBindable.Value?.Stars == BASE_STARS / 2); + + // hash code of 0 (the value) conflicts with the hash code of null (the initial/default value). + // it's important that the mod reference and its underlying bindable references stay the same to demonstrate this failure. + AddStep("change DA difficulty to 0", () => difficultyAdjust.OverallDifficulty.Value = 0); + AddUntilStep($"star difficulty -> 0", () => starDifficultyBindable.Value?.Stars == 0); + } + [Test] public void TestKeyEqualsWithDifferentModInstances() { From 995338029c78d000323dd6db66303042e8bdd153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Aug 2021 15:39:02 +0200 Subject: [PATCH 545/961] Fix difficulty cache lookups sharing underlying mod instances `DifficultyCacheLookup`s were storing raw `Mod` instances into their `OrderedMods` field. This could cause the cache lookups to wrongly succeed in cases of mods with settings. The particular case that triggered this fix was Difficulty Adjust. Because the difficulty cache is backed by a dictionary, there are two stages to the lookup; first `GetHashCode()` is used to find the appropriate hash bucket to look in, and then items from that hash bucket are compared against the key being searched for via the implementation of `Equals()`. As it turns out, the first hashing step ended up being the saving grace in most cases, as the hash computation included the values of the mod settings. But the Difficulty Adjust failure case was triggered by the quirk that `GetHashCode(0) == GetHashCode(null) == 0`. In such a case, the `Equals()` fallback was used. But as it turns out, because the `Mod` instance stored to lookups was not cloned and therefore potentially externally mutable, it could be polluted after being stored to the dictionary, and therefore breaking the equality check. Even though all of the setting values were compared, the hash bucket didn't match the actual contents of the lookup anymore (because they were mutated externally, e.g. by the user changing the mod setting values in the mod settings overlay). To resolve, clone out the mod structure before creating all difficulty lookups. --- osu.Game/Beatmaps/BeatmapDifficultyCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs index 5025e4ad4b..0aa6a6dd0b 100644 --- a/osu.Game/Beatmaps/BeatmapDifficultyCache.cs +++ b/osu.Game/Beatmaps/BeatmapDifficultyCache.cs @@ -310,7 +310,7 @@ namespace osu.Game.Beatmaps Beatmap = beatmap; // In the case that the user hasn't given us a ruleset, use the beatmap's default ruleset. Ruleset = ruleset ?? Beatmap.Ruleset; - OrderedMods = mods?.OrderBy(m => m.Acronym).ToArray() ?? Array.Empty(); + OrderedMods = mods?.OrderBy(m => m.Acronym).Select(mod => mod.DeepClone()).ToArray() ?? Array.Empty(); } public bool Equals(DifficultyCacheLookup other) From 43b3845970fefeb2998a3103b7caf565583feede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 21 Aug 2021 16:35:40 +0200 Subject: [PATCH 546/961] Remove redundant string interpolation --- osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs index 2b4dc48fe0..dcfeea5db8 100644 --- a/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs +++ b/osu.Game.Tests/Beatmaps/TestSceneBeatmapDifficultyCache.cs @@ -94,7 +94,7 @@ namespace osu.Game.Tests.Beatmaps // hash code of 0 (the value) conflicts with the hash code of null (the initial/default value). // it's important that the mod reference and its underlying bindable references stay the same to demonstrate this failure. AddStep("change DA difficulty to 0", () => difficultyAdjust.OverallDifficulty.Value = 0); - AddUntilStep($"star difficulty -> 0", () => starDifficultyBindable.Value?.Stars == 0); + AddUntilStep("star difficulty -> 0", () => starDifficultyBindable.Value?.Stars == 0); } [Test] From 2877b438242e7d2a9789a00db0ae882825697076 Mon Sep 17 00:00:00 2001 From: Nathan Alo Date: Sun, 22 Aug 2021 09:54:07 +0800 Subject: [PATCH 547/961] split multiplayer and playlist activity --- .../Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 3 +++ osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs | 3 +++ osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 3 --- osu.Game/Users/UserActivity.cs | 8 ++++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index ca1a3710ab..02c8e55caa 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -17,6 +17,7 @@ using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Ranking; +using osu.Game.Users; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer @@ -28,6 +29,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer // Disallow fails in multiplayer for now. protected override bool CheckModsAllowFailure() => false; + protected override UserActivity InitialActivity => new UserActivity.InMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + [Resolved] private MultiplayerClient client { get; set; } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 567ea6b988..246bdbc204 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; +using osu.Game.Users; namespace osu.Game.Screens.OnlinePlay.Playlists { @@ -20,6 +21,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public Action Exited; + protected override UserActivity InitialActivity => new UserActivity.InPlaylistGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); + public PlaylistsPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(playlistItem, configuration) { diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index f751fb747c..7ba12f5db6 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -6,7 +6,6 @@ using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Scoring; -using osu.Game.Users; namespace osu.Game.Screens.Play { @@ -20,8 +19,6 @@ namespace osu.Game.Screens.Play protected readonly PlaylistItem PlaylistItem; - protected override UserActivity InitialActivity => new UserActivity.InMultiplayerGame(Beatmap.Value.BeatmapInfo, Ruleset.Value); - protected RoomSubmittingPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) { diff --git a/osu.Game/Users/UserActivity.cs b/osu.Game/Users/UserActivity.cs index 88b91a3b42..75aa4866ff 100644 --- a/osu.Game/Users/UserActivity.cs +++ b/osu.Game/Users/UserActivity.cs @@ -50,6 +50,14 @@ namespace osu.Game.Users public override string Status => $@"{base.Status} with others"; } + public class InPlaylistGame : InGame + { + public InPlaylistGame(BeatmapInfo beatmap, RulesetInfo ruleset) + : base(beatmap, ruleset) + { + } + } + public class InSoloGame : InGame { public InSoloGame(BeatmapInfo info, RulesetInfo ruleset) From 3d402d9e788c1406eb997344887dc7ff4eb36da0 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Sun, 22 Aug 2021 10:13:34 +0800 Subject: [PATCH 548/961] List incompatible mods in tooltip of mod button --- osu.Game/Overlays/Mods/ModButton.cs | 6 +- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 145 +++++++++++++++++++++ 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Overlays/Mods/ModButtonTooltip.cs diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 572ff0d1aa..88cc706766 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Mods /// /// Represents a clickable button which can cycle through one of more mods. /// - public class ModButton : ModButtonEmpty, IHasTooltip + public class ModButton : ModButtonEmpty, IHasCustomTooltip { private ModIcon foregroundIcon; private ModIcon backgroundIcon; @@ -308,5 +308,9 @@ namespace osu.Game.Overlays.Mods Mod = mod; } + + public ITooltip GetCustomTooltip() => new ModButtonTooltip(); + + public object TooltipContent => SelectedMod ?? Mods[0]; } } diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs new file mode 100644 index 0000000000..2a3160e779 --- /dev/null +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -0,0 +1,145 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +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.Sprites; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play.HUD; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + public class ModButtonTooltip : VisibilityContainer, ITooltip + { + private readonly OsuSpriteText descriptionText; + private readonly Box background; + private readonly OsuSpriteText incompatibleText; + + private readonly Bindable> incompatibleMods = new Bindable>(); + + [Resolved] + private Bindable ruleset { get; set; } + + public ModButtonTooltip() + { + AutoSizeAxes = Axes.Both; + Masking = true; + CornerRadius = 5; + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Padding = new MarginPadding { Left = 10, Right = 10, Top = 5, Bottom = 5 }, + Children = new Drawable[] + { + descriptionText = new OsuSpriteText + { + Font = OsuFont.GetFont(weight: FontWeight.Regular), + Margin = new MarginPadding { Bottom = 5 } + }, + incompatibleText = new OsuSpriteText + { + Font = OsuFont.GetFont(weight: FontWeight.Regular), + Text = "Incompatible with:" + }, + new ModDisplay + { + Current = incompatibleMods, + ExpansionMode = ExpansionMode.AlwaysExpanded, + Scale = new Vector2(0.7f) + } + } + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + background.Colour = colours.Gray3; + descriptionText.Colour = colours.BlueLighter; + incompatibleText.Colour = colours.BlueLight; + } + + protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); + protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); + + private Drawable getModItem(Mod mod) + { + return new FillFlowContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new ModIcon(mod, false) + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.4f) + }, + new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 5 }, + Font = OsuFont.GetFont(weight: FontWeight.Regular), + Text = mod.Name, + }, + } + }; + } + + private string lastMod; + + public bool SetContent(object content) + { + if (!(content is Mod mod)) + return false; + + if (mod.Acronym == lastMod) return true; + + lastMod = mod.Acronym; + + descriptionText.Text = mod.Description; + + var incompatibleTypes = mod.IncompatibleMods; + + var allMods = ruleset.Value.CreateInstance().GetAllMods(); + + incompatibleMods.Value = allMods.Where(m => incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); + + if (!incompatibleMods.Value.Any()) + { + incompatibleText.Text = "Compatible with all mods"; + return true; + } + + incompatibleText.Text = "Incompatible with:"; + + return true; + } + + public void Move(Vector2 pos) => Position = pos; + } +} From ef6faf04be40955911b288d2b9b57b8cf21c7a10 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Sun, 22 Aug 2021 10:22:18 +0800 Subject: [PATCH 549/961] Use FirstOrDefault in TooltipContent --- osu.Game/Overlays/Mods/ModButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 88cc706766..9ad867c58a 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -311,6 +311,6 @@ namespace osu.Game.Overlays.Mods public ITooltip GetCustomTooltip() => new ModButtonTooltip(); - public object TooltipContent => SelectedMod ?? Mods[0]; + public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault(); } } From e213562b2a908b30a19b17e6182a08d9aa74c653 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Sun, 22 Aug 2021 11:01:17 +0800 Subject: [PATCH 550/961] Add a red tint on mods incompatible with the current selection --- osu.Game/Overlays/Mods/ModButton.cs | 38 +++++++++++++++++++++- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 2 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 9ad867c58a..359d1a7981 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -11,12 +11,16 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using System; +using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osu.Game.Utils; namespace osu.Game.Overlays.Mods { @@ -43,6 +47,9 @@ namespace osu.Game.Overlays.Mods // A selected index of -1 means not selected. private int selectedIndex = -1; + [Resolved] + private Bindable> globalSelectedMods { get; set; } + /// /// Change the selected mod index of this button. /// @@ -236,7 +243,28 @@ namespace osu.Game.Overlays.Mods backgroundIcon.Mod = foregroundIcon.Mod; foregroundIcon.Mod = mod; text.Text = mod.Name; - Colour = mod.HasImplementation ? Color4.White : Color4.Gray; + updateColour(mod); + } + + private Colour4 lightRed; + private Colour4 darkRed; + + private void updateColour(Mod mod) + { + var baseColour = mod.HasImplementation ? Color4.White : Color4.Gray; + + if (globalSelectedMods != null) + { + if (!globalSelectedMods.Value.Contains(mod)) + { + if (!ModUtils.CheckCompatibleSet(globalSelectedMods.Value.Concat(new[] { mod }))) + { + baseColour = mod.HasImplementation ? lightRed : darkRed; + } + } + } + + Colour = baseColour; } private void createIcons() @@ -309,6 +337,14 @@ namespace osu.Game.Overlays.Mods Mod = mod; } + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + lightRed = colour.RedLight; + darkRed = colour.RedDark; + globalSelectedMods.BindValueChanged(_ => updateColour(SelectedMod ?? Mods.FirstOrDefault()), true); + } + public ITooltip GetCustomTooltip() => new ModButtonTooltip(); public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault(); diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 2a3160e779..3383ad2d99 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.Mods var allMods = ruleset.Value.CreateInstance().GetAllMods(); - incompatibleMods.Value = allMods.Where(m => incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); + incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); if (!incompatibleMods.Value.Any()) { From 0bbddd297c9bc0ea1201005d761cf7b3f78ead0b Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Sun, 22 Aug 2021 11:05:53 +0800 Subject: [PATCH 551/961] Remove unused code --- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 30 ---------------------- 1 file changed, 30 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 3383ad2d99..1b889281f0 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -13,7 +13,6 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Rulesets.UI; using osu.Game.Screens.Play.HUD; using osuTK; @@ -81,35 +80,6 @@ namespace osu.Game.Overlays.Mods protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); - private Drawable getModItem(Mod mod) - { - return new FillFlowContainer - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - new ModIcon(mod, false) - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - AutoSizeAxes = Axes.Both, - Scale = new Vector2(0.4f) - }, - new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Margin = new MarginPadding { Left = 5 }, - Font = OsuFont.GetFont(weight: FontWeight.Regular), - Text = mod.Name, - }, - } - }; - } - private string lastMod; public bool SetContent(object content) From 9cd0a182f6b0267521b78f94e5852f4bc567ce35 Mon Sep 17 00:00:00 2001 From: Michael Malloy Date: Sun, 22 Aug 2021 00:26:35 -0500 Subject: [PATCH 552/961] Add null check for Android ruleset loading --- osu.Game/Rulesets/RulesetStore.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 1f12f3dfeb..4da3fc2b4f 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -30,7 +30,13 @@ namespace osu.Game.Rulesets // On android in release configuration assemblies are loaded from the apk directly into memory. // We cannot read assemblies from cwd, so should check loaded assemblies instead. loadFromAppDomain(); - loadFromDisk(); + + // This null check prevents Android from attempting to load the rulesets from disk. + // RuntimeInfo.StartupDirectory returns null on Android, and returns a path on other platforms. + if (RuntimeInfo.StartupDirectory != null) + { + loadFromDisk(); + } // the event handler contains code for resolving dependency on the game assembly for rulesets located outside the base game directory. // It needs to be attached to the assembly lookup event before the actual call to loadUserRulesets() else rulesets located out of the base game directory will fail From 956112eb103da73a89cc2895693cb050eff512b1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 22 Aug 2021 12:40:41 +0300 Subject: [PATCH 553/961] Reword comment and remove brackets --- osu.Game/Rulesets/RulesetStore.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 4da3fc2b4f..a9e04a02b5 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -31,12 +31,11 @@ namespace osu.Game.Rulesets // We cannot read assemblies from cwd, so should check loaded assemblies instead. loadFromAppDomain(); - // This null check prevents Android from attempting to load the rulesets from disk. - // RuntimeInfo.StartupDirectory returns null on Android, and returns a path on other platforms. + // This null check prevents Android from attempting to load the rulesets from disk, + // as the underlying path "AppContext.BaseDirectory", despite being non-nullable, it returns null on android. + // See https://github.com/xamarin/xamarin-android/issues/3489. if (RuntimeInfo.StartupDirectory != null) - { loadFromDisk(); - } // the event handler contains code for resolving dependency on the game assembly for rulesets located outside the base game directory. // It needs to be attached to the assembly lookup event before the actual call to loadUserRulesets() else rulesets located out of the base game directory will fail From 81e3c9d40f7aa6bc8d439a4bf45f0c605c9a38e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 22 Aug 2021 19:13:21 +0900 Subject: [PATCH 554/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8fd761691c..cae8a946a3 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 0abd9adf77..bac99a098d 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index d03985a0c2..f3ecc90bea 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From d164529be8cb0ab5eda29a454e96abf2174ca934 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 22 Aug 2021 15:29:24 +0300 Subject: [PATCH 555/961] Fix ruleset selector not updating to the first ruleset item until after `LoadComplete()` This fixes the whole issue behind `Ruleset.Value` being null, by updating `Current` on BDL rather than waiting for the base logic which executes at `LoadComplete`. This seems like something that should happen at the base `TabControl` class itself, by switching `Current` right after the first added tab item, rather than doing it on `LoadComplete`, but I'm not sure about changing framework logic outright, so fixing this locally until it occurs on other places. --- osu.Game/Rulesets/RulesetSelector.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index 8e6ec556d2..e4d8f89a22 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.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.Graphics.UserInterface; using osu.Framework.Allocation; @@ -18,6 +19,12 @@ namespace osu.Game.Rulesets { foreach (var r in Rulesets.AvailableRulesets) AddItem(r); + + // This is supposed to be an implicit process in the base class, but the problem is that it happens in LoadComplete. + // That can become an issue with overlays that require access to the initial ruleset value + // before the ruleset selectors reached a LoadComplete state. + // (e.g. displaying RankingsOverlay for the first time). + Current.Value = Items.First(); } } } From 45b8bd175c6ae9806f13250658383be901658f2e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 22 Aug 2021 15:29:47 +0300 Subject: [PATCH 556/961] Decouple rankings overlay's ruleset bindable from game-wide bindable --- osu.Game/Overlays/RankingsOverlay.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index a093969115..65c9c4d953 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -15,6 +15,7 @@ namespace osu.Game.Overlays { public class RankingsOverlay : TabbableOnlineOverlay { + protected Bindable Ruleset => Header.Ruleset; protected Bindable Country => Header.Country; private APIRequest lastRequest; @@ -22,9 +23,6 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } - [Resolved] - private Bindable ruleset { get; set; } - public RankingsOverlay() : base(OverlayColourScheme.Green) { @@ -34,8 +32,6 @@ namespace osu.Game.Overlays { base.LoadComplete(); - Header.Ruleset.BindTo(ruleset); - Country.BindValueChanged(_ => { // if a country is requested, force performance scope. @@ -45,7 +41,7 @@ namespace osu.Game.Overlays Scheduler.AddOnce(triggerTabChanged); }); - ruleset.BindValueChanged(_ => + Ruleset.BindValueChanged(_ => { if (Header.Current.Value == RankingsScope.Spotlights) return; @@ -85,7 +81,7 @@ namespace osu.Game.Overlays { LoadDisplay(new SpotlightsLayout { - Ruleset = { BindTarget = ruleset } + Ruleset = { BindTarget = Ruleset } }); return; } @@ -110,13 +106,13 @@ namespace osu.Game.Overlays switch (Header.Current.Value) { case RankingsScope.Performance: - return new GetUserRankingsRequest(ruleset.Value, country: Country.Value?.FlagName); + return new GetUserRankingsRequest(Ruleset.Value, country: Country.Value?.FlagName); case RankingsScope.Country: - return new GetCountryRankingsRequest(ruleset.Value); + return new GetCountryRankingsRequest(Ruleset.Value); case RankingsScope.Score: - return new GetUserRankingsRequest(ruleset.Value, UserRankingsType.Score); + return new GetUserRankingsRequest(Ruleset.Value, UserRankingsType.Score); } return null; From 9816af688eb78a9181164761e170be53b9194586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 14:26:53 +0200 Subject: [PATCH 557/961] Add basic design settings to setup screen --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 58 ++++++++++++++++++++ osu.Game/Screens/Edit/Setup/SetupScreen.cs | 3 +- 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Screens/Edit/Setup/DesignSection.cs diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs new file mode 100644 index 0000000000..380b29b04b --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Localisation; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Screens.Edit.Setup +{ + internal class DesignSection : SetupSection + { + private LabelledSwitchButton widescreenSupport; + private LabelledSwitchButton epilepsyWarning; + private LabelledSwitchButton letterboxDuringBreaks; + + public override LocalisableString Title => "Design"; + + [BackgroundDependencyLoader] + private void load() + { + Children = new[] + { + widescreenSupport = new LabelledSwitchButton + { + Label = "Widescreen support", + Current = { Value = Beatmap.BeatmapInfo.WidescreenStoryboard } + }, + epilepsyWarning = new LabelledSwitchButton + { + Label = "Epilepsy warning", + Description = "Setting this is recommended if the storyboard contains scenes with rapidly flashing colours.", + Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning } + }, + letterboxDuringBreaks = new LabelledSwitchButton + { + Label = "Letterbox during breaks", + Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); + epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); + letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); + } + + private void updateBeatmap() + { + Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value; + Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; + Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value; + } + } +} diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 5bbec2574f..72bf3ad67e 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -34,7 +34,8 @@ namespace osu.Game.Screens.Edit.Setup new ResourcesSection(), new MetadataSection(), new DifficultySection(), - new ColoursSection() + new ColoursSection(), + new DesignSection(), } }, }); From d602dc9d908ddcfc9470b9bda7c6c7303416bdf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 14:28:16 +0200 Subject: [PATCH 558/961] Enable epilepsy warning setting persistence in encoder --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index f14f6ec10c..524b556ddc 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -93,8 +93,8 @@ namespace osu.Game.Beatmaps.Formats // writer.WriteLine(@"OverlayPosition: " + b.OverlayPosition); // if (!string.IsNullOrEmpty(b.SkinPreference)) // writer.WriteLine(@"SkinPreference:" + b.SkinPreference); - // if (b.EpilepsyWarning) - // writer.WriteLine(@"EpilepsyWarning: 1"); + if (beatmap.BeatmapInfo.EpilepsyWarning) + writer.WriteLine(@"EpilepsyWarning: 1"); // if (b.CountdownOffset > 0) // writer.WriteLine(@"CountdownOffset: " + b.CountdownOffset.ToString()); if (beatmap.BeatmapInfo.RulesetID == 3) From e4a8f72167e2239a0254ded972dc2b0f27b7e000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 19:01:26 +0200 Subject: [PATCH 559/961] Add failing test case --- .../SongSelect/TestSceneBeatmapInfoWedge.cs | 26 +++++++++++++++++++ osu.Game/Screens/Select/BeatmapInfoWedge.cs | 3 +++ 2 files changed, 29 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs index 2b38c4f936..9fa0eab548 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapInfoWedge.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using System.Globalization; using System.Linq; using JetBrains.Annotations; using NUnit.Framework; @@ -11,6 +12,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; @@ -19,6 +21,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Legacy; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Taiko; using osu.Game.Screens.Select; using osuTK; @@ -141,6 +144,29 @@ namespace osu.Game.Tests.Visual.SongSelect selectBeatmap(createLongMetadata()); } + [Test] + public void TestBPMUpdates() + { + const float bpm = 120; + IBeatmap beatmap = createTestBeatmap(new OsuRuleset().RulesetInfo); + beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 60 * 1000 / bpm }); + + OsuModDoubleTime doubleTime = null; + + selectBeatmap(beatmap); + checkDisplayedBPM(bpm); + + AddStep("select DT", () => SelectedMods.Value = new[] { doubleTime = new OsuModDoubleTime() }); + checkDisplayedBPM(bpm * 1.5f); + + AddStep("change DT rate", () => doubleTime.SpeedChange.Value = 2); + checkDisplayedBPM(bpm * 2); + + void checkDisplayedBPM(float target) => + AddUntilStep($"displayed bpm is {target}", () => this.ChildrenOfType().Any( + label => label.Statistic.Name == "BPM" && label.Statistic.Content == target.ToString(CultureInfo.InvariantCulture))); + } + private void selectBeatmap([CanBeNull] IBeatmap b) { Container containerBefore = null; diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 297a16dd1d..1769381a58 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -449,8 +449,11 @@ namespace osu.Game.Screens.Select { public LocalisableString TooltipText { get; } + internal BeatmapStatistic Statistic { get; } + public InfoLabel(BeatmapStatistic statistic) { + Statistic = statistic; TooltipText = statistic.Name; AutoSizeAxes = Axes.Both; From 9538a32b5ec0fbe7ea7fdf0a2012743b84fe877a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 19:05:44 +0200 Subject: [PATCH 560/961] Explicitly update beatmap info wedge on mod change This used to already be the case prior to b419ea7, but in a very roundabout way. Changes to the value of the star difficulty bindable - including indirect changes via the set of active mods changing - would trigger the wedge display to regenerate and load asynchronously. b419ea7 accidentally broke this by moving down the bindable retrieval to a lower level, at which point `WedgeInfoText` would only receive the set of mods selected at the time at which a given beatmap was selected, and not receive any further updates, breaking the BPM display updating in real time (as `WedgeInfoText` could not be aware that rate-changing mods were even in effect). To resolve, explicitly reload the wedge's contents on mod changes. --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 1769381a58..d40e21cd5e 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -71,6 +71,7 @@ namespace osu.Game.Screens.Select private void load() { ruleset.BindValueChanged(_ => updateDisplay()); + mods.BindValueChanged(_ => updateDisplay()); } private const double animation_duration = 800; From 2e80e2be5146f0f7d54c476d6c9530b2f7abf96d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 21:47:37 +0200 Subject: [PATCH 561/961] Reword epilepsy warning description text --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 380b29b04b..ce6b4fa034 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Setup epilepsyWarning = new LabelledSwitchButton { Label = "Epilepsy warning", - Description = "Setting this is recommended if the storyboard contains scenes with rapidly flashing colours.", + Description = "Recommended if the storyboard contains scenes with rapidly flashing colours.", Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning } }, letterboxDuringBreaks = new LabelledSwitchButton From 4f3a5fbad5245ef37b73a6123b136f94eb61f128 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 23 Aug 2021 14:29:15 +0900 Subject: [PATCH 562/961] Fix test failure --- .../TestScenePlaylistsLoungeSubScreen.cs | 20 ++++++++++++------- .../OnlinePlay/Lounge/LoungeSubScreen.cs | 15 +++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index a4bcb4baae..dafa8300f6 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -3,10 +3,11 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Bindables; using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Graphics.Containers; -using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Playlists; using osu.Game.Tests.Visual.OnlinePlay; @@ -18,13 +19,13 @@ namespace osu.Game.Tests.Visual.Playlists { protected new TestRequestHandlingRoomManager RoomManager => (TestRequestHandlingRoomManager)base.RoomManager; - private LoungeSubScreen loungeScreen; + private TestLoungeSubScreen loungeScreen; public override void SetUpSteps() { base.SetUpSteps(); - AddStep("push screen", () => LoadScreen(loungeScreen = new PlaylistsLoungeSubScreen())); + AddStep("push screen", () => LoadScreen(loungeScreen = new TestLoungeSubScreen())); AddUntilStep("wait for present", () => loungeScreen.IsCurrentScreen()); } @@ -69,21 +70,26 @@ namespace osu.Game.Tests.Visual.Playlists { AddStep("add rooms", () => RoomManager.AddRooms(1)); - AddAssert("selected room is not disabled", () => !OnlinePlayDependencies.SelectedRoom.Disabled); + AddAssert("selected room is not disabled", () => !loungeScreen.SelectedRoom.Disabled); AddStep("select room", () => roomsContainer.Rooms[0].TriggerClick()); - AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null); + AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null); AddStep("enter room", () => roomsContainer.Rooms[0].TriggerClick()); AddUntilStep("wait for match load", () => Stack.CurrentScreen is PlaylistsRoomSubScreen); - AddAssert("selected room is non-null", () => OnlinePlayDependencies.SelectedRoom.Value != null); - AddAssert("selected room is disabled", () => OnlinePlayDependencies.SelectedRoom.Disabled); + AddAssert("selected room is non-null", () => loungeScreen.SelectedRoom.Value != null); + AddAssert("selected room is disabled", () => loungeScreen.SelectedRoom.Disabled); } private bool checkRoomVisible(DrawableRoom room) => loungeScreen.ChildrenOfType().First().ScreenSpaceDrawQuad .Contains(room.ScreenSpaceDrawQuad.Centre); + + private class TestLoungeSubScreen : PlaylistsLoungeSubScreen + { + public new Bindable SelectedRoom => base.SelectedRoom; + } } } diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index 7e898db584..cf3d76a3fb 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -38,7 +38,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected override BackgroundScreen CreateBackground() => new LoungeBackgroundScreen { - SelectedRoom = { BindTarget = selectedRoom } + SelectedRoom = { BindTarget = SelectedRoom } }; protected override UserActivity InitialActivity => new UserActivity.SearchingForLobby(); @@ -52,6 +52,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected ListingPollingComponent ListingPollingComponent { get; private set; } + protected readonly Bindable SelectedRoom = new Bindable(); + [Resolved] private MusicController music { get; set; } @@ -68,7 +70,6 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private LeasedBindable selectionLease; private readonly Bindable filter = new Bindable(new FilterCriteria()); - private readonly Bindable selectedRoom = new Bindable(); private readonly IBindable operationInProgress = new Bindable(); private readonly IBindable isIdle = new BindableBool(); private LoadingLayer loadingLayer; @@ -105,7 +106,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge Child = roomsContainer = new RoomsContainer { Filter = { BindTarget = filter }, - SelectedRoom = { BindTarget = selectedRoom } + SelectedRoom = { BindTarget = SelectedRoom } } }, }, @@ -164,7 +165,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge }; // scroll selected room into view on selection. - selectedRoom.BindValueChanged(val => + SelectedRoom.BindValueChanged(val => { var drawable = roomsContainer.Rooms.FirstOrDefault(r => r.Room == val.NewValue); if (drawable != null) @@ -247,8 +248,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge selectionLease.Return(); selectionLease = null; - if (selectedRoom.Value?.RoomID.Value == null) - selectedRoom.Value = new Room(); + if (SelectedRoom.Value?.RoomID.Value == null) + SelectedRoom.Value = new Room(); music?.EnsurePlayingSomething(); @@ -321,7 +322,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge protected virtual void OpenNewRoom(Room room) { - selectionLease = selectedRoom.BeginLease(false); + selectionLease = SelectedRoom.BeginLease(false); Debug.Assert(selectionLease != null); selectionLease.Value = room; From 58fb0c042bb060f7ba0769c22ccc75a2ad105aaf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 14:30:34 +0900 Subject: [PATCH 563/961] Remove background scale altogether I'm not sure why this is required. Seems like something which was meant to exist to handle parallax, but that is already handled elsewhere now. --- osu.Game/Screens/BackgroundScreenStack.cs | 6 ------ .../OnlinePlay/Components/OnlinePlayBackgroundScreen.cs | 8 -------- 2 files changed, 14 deletions(-) diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs index 17894d2474..294f23d2ac 100644 --- a/osu.Game/Screens/BackgroundScreenStack.cs +++ b/osu.Game/Screens/BackgroundScreenStack.cs @@ -4,25 +4,19 @@ using System.Collections.Generic; using osu.Framework.Graphics; using osu.Framework.Screens; -using osuTK; namespace osu.Game.Screens { public class BackgroundScreenStack : ScreenStack { - public const float BACKGROUND_SCALE = 1.06f; - public BackgroundScreenStack() : base(false) { - Scale = new Vector2(BACKGROUND_SCALE); RelativeSizeAxes = Axes.Both; Anchor = Anchor.Centre; Origin = Anchor.Centre; } - //public float ParallaxAmount { set => parallax.ParallaxAmount = ParallaxContainer.DEFAULT_PARALLAX_AMOUNT * value; } - public void Push(BackgroundScreen screen) { if (screen == null) diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs index 5077979bf0..a282f1dacf 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs @@ -77,14 +77,6 @@ namespace osu.Game.Screens.OnlinePlay.Components AddInternal(background = newBackground); } - protected override void Update() - { - base.Update(); - - // This is a static screen, so override the scale set in base.Update(), but also the scale set by the screen stack. - Scale = new Vector2(1f / BackgroundScreenStack.BACKGROUND_SCALE); - } - public override void OnSuspending(IScreen next) { base.OnSuspending(next); From 2ba88923b624d012c69c99d40b834beab47e407e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 08:41:14 +0300 Subject: [PATCH 564/961] Select user preferred ruleset on overlay ruleset selectors initially --- osu.Game/Overlays/OverlayRulesetSelector.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index 8c44157f78..74b8d0d3be 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Game.Online.API; using osu.Game.Rulesets; using osuTK; @@ -16,6 +18,15 @@ namespace osu.Game.Overlays AutoSizeAxes = Axes.Both; } + [BackgroundDependencyLoader] + private void load(RulesetStore store, IAPIProvider api) + { + var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); + + if (preferredRuleset != null) + Current.Value = preferredRuleset; + } + protected override TabItem CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer From 99bb3032a54c5a65d10bf2be009c75f3edeefc00 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 15:26:39 +0900 Subject: [PATCH 565/961] Move gradient to be part of the background for now --- .../Components/OnlinePlayBackgroundScreen.cs | 10 ++++++++++ .../Screens/OnlinePlay/OnlinePlaySubScreenStack.cs | 14 -------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs index a282f1dacf..6ce5f6a6db 100644 --- a/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Components/OnlinePlayBackgroundScreen.cs @@ -3,10 +3,14 @@ using System.Threading; using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; using osu.Game.Online.Rooms; using osuTK; +using osuTK.Graphics; #nullable enable @@ -20,6 +24,12 @@ namespace osu.Game.Screens.OnlinePlay.Components protected OnlinePlayBackgroundScreen() : base(false) { + AddInternal(new Box + { + RelativeSizeAxes = Axes.Both, + Depth = float.MinValue, + Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f)) + }); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs index 69fa3b0916..7f2a0980c1 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySubScreenStack.cs @@ -1,26 +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.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Colour; -using osu.Framework.Graphics.Shapes; using osu.Framework.Screens; -using osuTK.Graphics; namespace osu.Game.Screens.OnlinePlay { public class OnlinePlaySubScreenStack : OsuScreenStack { - public OnlinePlaySubScreenStack() - { - AddInternal(new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientVertical(Color4.Black.Opacity(0.9f), Color4.Black.Opacity(0.6f)) - }); - } - protected override void ScreenChanged(IScreen prev, IScreen next) { base.ScreenChanged(prev, next); From 1d89d757af12ca677aac1892a02256d9618b13d1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 09:56:00 +0300 Subject: [PATCH 566/961] Fix beatmap ruleset selector selecting initial ruleset --- .../BeatmapSet/BeatmapRulesetSelector.cs | 3 +++ osu.Game/Overlays/OverlayRulesetSelector.cs | 9 ++++++--- osu.Game/Rulesets/RulesetSelector.cs | 20 ++++++++++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 005d21726b..c46a3966ee 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -6,11 +6,14 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; using osu.Game.Rulesets; using System.Linq; +using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { public class BeatmapRulesetSelector : OverlayRulesetSelector { + protected override bool SelectInitialRuleset => false; + private readonly Bindable beatmapSet = new Bindable(); public BeatmapSetInfo BeatmapSet diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index 74b8d0d3be..60b16abd48 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -21,10 +21,13 @@ namespace osu.Game.Overlays [BackgroundDependencyLoader] private void load(RulesetStore store, IAPIProvider api) { - var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); + if (SelectInitialRuleset) + { + var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); - if (preferredRuleset != null) - Current.Value = preferredRuleset; + if (preferredRuleset != null) + Current.Value = preferredRuleset; + } } protected override TabItem CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value); diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index e4d8f89a22..e5d39fa144 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.cs @@ -14,17 +14,27 @@ namespace osu.Game.Rulesets protected override Dropdown CreateDropdown() => null; + protected virtual bool SelectInitialRuleset => true; + + protected RulesetSelector() + { + SelectFirstTabByDefault = false; + } + [BackgroundDependencyLoader] private void load() { foreach (var r in Rulesets.AvailableRulesets) AddItem(r); - // This is supposed to be an implicit process in the base class, but the problem is that it happens in LoadComplete. - // That can become an issue with overlays that require access to the initial ruleset value - // before the ruleset selectors reached a LoadComplete state. - // (e.g. displaying RankingsOverlay for the first time). - Current.Value = Items.First(); + if (SelectInitialRuleset) + { + // This is supposed to be an implicit process in the base class, but the problem is that it happens in LoadComplete. + // That can become an issue with overlays that require access to the initial ruleset value + // before the ruleset selectors reached a LoadComplete state. + // (e.g. displaying RankingsOverlay for the first time). + Current.Value = Items.First(); + } } } } From f2d51200a5b53a66251aca60fc1d98a749ba94c3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 16:55:42 +0900 Subject: [PATCH 567/961] Update android mime types in line with new specifications --- osu.Android/OsuGameActivity.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/osu.Android/OsuGameActivity.cs b/osu.Android/OsuGameActivity.cs index 063e02d349..0bcbfc4baf 100644 --- a/osu.Android/OsuGameActivity.cs +++ b/osu.Android/OsuGameActivity.cs @@ -20,8 +20,21 @@ namespace osu.Android [Activity(Theme = "@android:style/Theme.NoTitleBar", MainLauncher = true, ScreenOrientation = ScreenOrientation.FullUser, SupportsPictureInPicture = false, ConfigurationChanges = ConfigChanges.Orientation | ConfigChanges.ScreenSize, HardwareAccelerated = false, LaunchMode = LaunchMode.SingleInstance, Exported = true)] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osz", DataHost = "*", DataMimeType = "*/*")] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataPathPattern = ".*\\\\.osk", DataHost = "*", DataMimeType = "*/*")] - [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-archive")] - [IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] { "application/zip", "application/octet-stream", "application/download", "application/x-zip", "application/x-zip-compressed", "application/x-osu-archive" })] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-beatmap-archive")] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-skin-archive")] + [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault }, DataScheme = "content", DataMimeType = "application/x-osu-replay")] + [IntentFilter(new[] { Intent.ActionSend, Intent.ActionSendMultiple }, Categories = new[] { Intent.CategoryDefault }, DataMimeTypes = new[] + { + "application/zip", + "application/octet-stream", + "application/download", + "application/x-zip", + "application/x-zip-compressed", + // newer official mime types (see https://osu.ppy.sh/wiki/en/osu%21_File_Formats). + "application/x-osu-beatmap-archive", + "application/x-osu-skin-archive", + "application/x-osu-replay", + })] [IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataSchemes = new[] { "osu", "osump" })] public class OsuGameActivity : AndroidGameActivity { @@ -66,12 +79,14 @@ namespace osu.Android case Intent.ActionSendMultiple: { var uris = new List(); + for (int i = 0; i < intent.ClipData?.ItemCount; i++) { var content = intent.ClipData?.GetItemAt(i); if (content != null) uris.Add(content.Uri); } + handleImportFromUris(uris.ToArray()); break; } From cb7c2f713be7cfeb6e667df1404a843773ae83ca Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 11:09:26 +0300 Subject: [PATCH 568/961] Store default ruleset value for ability to revert --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 1 - osu.Game/Overlays/OverlayRulesetSelector.cs | 2 +- osu.Game/Rulesets/RulesetSelector.cs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index c46a3966ee..3e707fc091 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; using osu.Game.Rulesets; using System.Linq; -using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index 60b16abd48..3f562e933d 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); if (preferredRuleset != null) - Current.Value = preferredRuleset; + Current.Value = Current.Default = preferredRuleset; } } diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index e5d39fa144..998948140e 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets // That can become an issue with overlays that require access to the initial ruleset value // before the ruleset selectors reached a LoadComplete state. // (e.g. displaying RankingsOverlay for the first time). - Current.Value = Items.First(); + Current.Value = Current.Default = Items.First(); } } } From 9fa39cd34e867be4d1258b52f427cfb5eb0cbb6b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 11:11:06 +0300 Subject: [PATCH 569/961] Revert ruleset when not applied filters (includes scope change) --- osu.Game/Overlays/RankingsOverlay.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 65c9c4d953..9ddcaa589e 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -18,6 +18,8 @@ namespace osu.Game.Overlays protected Bindable Ruleset => Header.Ruleset; protected Bindable Country => Header.Country; + private bool requiresRulesetRevert; + private APIRequest lastRequest; [Resolved] @@ -50,6 +52,25 @@ namespace osu.Game.Overlays }); } + protected override void PopIn() + { + base.PopIn(); + + if (requiresRulesetRevert) + { + Ruleset.SetDefault(); + requiresRulesetRevert = false; + } + } + + protected override void PopOutComplete() + { + base.PopOutComplete(); + + if (Header.Current.Value == default && Country.Value == null) + requiresRulesetRevert = true; + } + protected override void OnTabChanged(RankingsScope tab) { // country filtering is only valid for performance scope. From 391c4e529c4fa847385c5052e6788b1968348ef6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 11:11:15 +0300 Subject: [PATCH 570/961] Add test coverage for all added features --- .../Visual/Online/TestSceneRankingsOverlay.cs | 42 +++++++++++++++++++ .../TestSceneOverlayRulesetSelector.cs | 22 ++++++++++ 2 files changed, 64 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index aff510dd95..74b8cbdfe5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -1,12 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using osu.Framework.Allocation; using osu.Game.Overlays; using NUnit.Framework; using osu.Game.Users; using osu.Framework.Bindables; +using osu.Framework.Testing; using osu.Game.Overlays.Rankings; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Taiko; namespace osu.Game.Tests.Visual.Online { @@ -35,6 +39,44 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show", rankingsOverlay.Show); } + [Test] + public void TestRulesetResetsOnNoFilters() + { + AddStep("Set different ruleset", () => rankingsOverlay.ChildrenOfType().Single().SwitchTab(1)); + AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); + AddStep("Hide overlay", () => rankingsOverlay.Hide()); + AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); + + AddStep("Show overlay again", () => rankingsOverlay.Show()); + AddAssert("Ruleset reverted", () => rankingsOverlay.Header.Ruleset.IsDefault); + } + + [Test] + public void TestRulesetDoesntResetOnCountryFilter() + { + AddStep("Set different ruleset", () => rankingsOverlay.ChildrenOfType().Single().SwitchTab(1)); + AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); + AddStep("Set country filter", () => countryBindable.Value = us_country); + AddStep("Hide overlay", () => rankingsOverlay.Hide()); + AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); + + AddStep("Show overlay again", () => rankingsOverlay.Show()); + AddAssert("Ruleset not reverted", () => !rankingsOverlay.Header.Ruleset.IsDefault); + } + + [Test] + public void TestRulesetDoesntResetOnScopeChange() + { + AddStep("Set ruleset to osu!taiko", () => rankingsOverlay.Header.Ruleset.Value = new TaikoRuleset().RulesetInfo); + AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); + AddStep("Set different scope", () => scope.Value = RankingsScope.Score); + AddStep("Hide overlay", () => rankingsOverlay.Hide()); + AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); + + AddStep("Show overlay again", () => rankingsOverlay.Show()); + AddAssert("Ruleset not reverted", () => !rankingsOverlay.Header.Ruleset.IsDefault); + } + [Test] public void TestFlagScopeDependency() { diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs index f4fa41a3b7..ceec8b2e58 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs @@ -70,5 +70,27 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Select catch", () => ruleset.Value = new CatchRuleset().RulesetInfo); AddAssert("Check catch selected", () => selector.Current.Value.Equals(new CatchRuleset().RulesetInfo)); } + + [Test] + public void TestUserPreferredRuleset() + { + OverlayRulesetSelector localSelector = null; + + AddStep("Set osu! preferred ruleset", () => API.LocalUser.Value.PlayMode = OsuRuleset.SHORT_NAME); + AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddAssert("Check osu! selected", () => localSelector.Current.Value.Equals(new OsuRuleset().RulesetInfo)); + + AddStep("Set osu!taiko preferred ruleset", () => API.LocalUser.Value.PlayMode = TaikoRuleset.SHORT_NAME); + AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddAssert("Check osu!taiko selected", () => localSelector.Current.Value.Equals(new TaikoRuleset().RulesetInfo)); + + AddStep("Set osu!catch preferred ruleset", () => API.LocalUser.Value.PlayMode = CatchRuleset.SHORT_NAME); + AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddAssert("Check osu!catch selected", () => localSelector.Current.Value.Equals(new CatchRuleset().RulesetInfo)); + + AddStep("Set osu!mania preferred ruleset", () => API.LocalUser.Value.PlayMode = ManiaRuleset.SHORT_NAME); + AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddAssert("Check osu!mania selected", () => localSelector.Current.Value.Equals(new ManiaRuleset().RulesetInfo)); + } } } From 1de84e1c9806beb54eaae23b415cc2279c8a38be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 17:34:19 +0900 Subject: [PATCH 571/961] Change description to include mention of video Co-authored-by: Joseph Madamba --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index ce6b4fa034..3f54ba9c9b 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Edit.Setup epilepsyWarning = new LabelledSwitchButton { Label = "Epilepsy warning", - Description = "Recommended if the storyboard contains scenes with rapidly flashing colours.", + Description = "Recommended if the storyboard or video contain scenes with rapidly flashing colours.", Current = { Value = Beatmap.BeatmapInfo.EpilepsyWarning } }, letterboxDuringBreaks = new LabelledSwitchButton From d17f7b5c8bab129ac3d1e219177b63e5dfe6b248 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 17:40:41 +0900 Subject: [PATCH 572/961] Side `WidescreenStoryboard` to on by default for new beatmaps --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 241649062e..27aa874dc9 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -128,6 +128,7 @@ namespace osu.Game.Beatmaps BaseDifficulty = new BeatmapDifficulty(), Ruleset = ruleset, Metadata = metadata, + WidescreenStoryboard = true, } } }; From 2f6b95da39129c6bfcfa74b34a69ec9611bcf43c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 17:41:03 +0900 Subject: [PATCH 573/961] Add descriptions for the remaining settings --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 3f54ba9c9b..68aaf3dd76 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -23,6 +23,7 @@ namespace osu.Game.Screens.Edit.Setup widescreenSupport = new LabelledSwitchButton { Label = "Widescreen support", + Description = "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area.", Current = { Value = Beatmap.BeatmapInfo.WidescreenStoryboard } }, epilepsyWarning = new LabelledSwitchButton @@ -34,6 +35,7 @@ namespace osu.Game.Screens.Edit.Setup letterboxDuringBreaks = new LabelledSwitchButton { Label = "Letterbox during breaks", + Description = "Adds horizontal letterboxing to give a cinematic look during breaks.", Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks } } }; From 79aea1fb7834a4513f7153bc8e6f9b8359bfe518 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 11:44:50 +0300 Subject: [PATCH 574/961] Fix test overlay ruleset selectors not surrounded with overlay colour providers --- .../UserInterface/TestSceneOverlayRulesetSelector.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs index ceec8b2e58..de55914fa8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs @@ -77,19 +77,19 @@ namespace osu.Game.Tests.Visual.UserInterface OverlayRulesetSelector localSelector = null; AddStep("Set osu! preferred ruleset", () => API.LocalUser.Value.PlayMode = OsuRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); AddAssert("Check osu! selected", () => localSelector.Current.Value.Equals(new OsuRuleset().RulesetInfo)); AddStep("Set osu!taiko preferred ruleset", () => API.LocalUser.Value.PlayMode = TaikoRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); AddAssert("Check osu!taiko selected", () => localSelector.Current.Value.Equals(new TaikoRuleset().RulesetInfo)); AddStep("Set osu!catch preferred ruleset", () => API.LocalUser.Value.PlayMode = CatchRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); AddAssert("Check osu!catch selected", () => localSelector.Current.Value.Equals(new CatchRuleset().RulesetInfo)); AddStep("Set osu!mania preferred ruleset", () => API.LocalUser.Value.PlayMode = ManiaRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = localSelector = new OverlayRulesetSelector()); + AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); AddAssert("Check osu!mania selected", () => localSelector.Current.Value.Equals(new ManiaRuleset().RulesetInfo)); } } From c2c9a93e2c721b16947e5fa797e41a84a2584845 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 18:12:35 +0900 Subject: [PATCH 575/961] Show editor file choosers in a popover rather than inline Supersedes and closes #14370. Closes #14367. --- .../Edit/Setup/FileChooserLabelledTextBox.cs | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index 69c27702f8..e68e581942 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs @@ -8,22 +8,27 @@ using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Database; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; +using osuTK; namespace osu.Game.Screens.Edit.Setup { /// /// A labelled textbox which reveals an inline file chooser when clicked. /// - internal class FileChooserLabelledTextBox : LabelledTextBox, ICanAcceptFiles + internal class FileChooserLabelledTextBox : LabelledTextBox, ICanAcceptFiles, IHasPopover { private readonly string[] handledExtensions; + public IEnumerable HandledExtensions => handledExtensions; /// @@ -51,23 +56,9 @@ namespace osu.Game.Screens.Edit.Setup Origin = Anchor.Centre, RelativeSizeAxes = Axes.X, CornerRadius = CORNER_RADIUS, - OnFocused = DisplayFileChooser + OnFocused = this.ShowPopover }; - public void DisplayFileChooser() - { - OsuFileSelector fileSelector; - - Target.Child = fileSelector = new OsuFileSelector(currentFile.Value?.DirectoryName, handledExtensions) - { - RelativeSizeAxes = Axes.X, - Height = 400, - CurrentFile = { BindTarget = currentFile } - }; - - sectionsContainer.ScrollTo(fileSelector); - } - protected override void LoadComplete() { base.LoadComplete(); @@ -111,5 +102,23 @@ namespace osu.Game.Screens.Edit.Setup GetContainingInputManager().TriggerFocusContention(this); } } + + public Popover GetPopover() => new FileChooserPopover(handledExtensions, currentFile); + + private class FileChooserPopover : OsuPopover + { + public FileChooserPopover(string[] handledExtensions, Bindable currentFile) + { + Child = new Container + { + Size = new Vector2(600, 400), + Child = new OsuFileSelector(currentFile.Value?.DirectoryName, handledExtensions) + { + RelativeSizeAxes = Axes.Both, + CurrentFile = { BindTarget = currentFile } + }, + }; + } + } } } From eeeaefbd7d0c87baeb65c0b08fa1c3364ea88c5c Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 12:38:24 +0300 Subject: [PATCH 576/961] Revert "Store default ruleset value for ability to revert" This reverts commit cb7c2f713be7cfeb6e667df1404a843773ae83ca. --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 1 + osu.Game/Overlays/OverlayRulesetSelector.cs | 2 +- osu.Game/Rulesets/RulesetSelector.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 3e707fc091..c46a3966ee 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -6,6 +6,7 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; using osu.Game.Rulesets; using System.Linq; +using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index 3f562e933d..60b16abd48 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); if (preferredRuleset != null) - Current.Value = Current.Default = preferredRuleset; + Current.Value = preferredRuleset; } } diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index 998948140e..e5d39fa144 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets // That can become an issue with overlays that require access to the initial ruleset value // before the ruleset selectors reached a LoadComplete state. // (e.g. displaying RankingsOverlay for the first time). - Current.Value = Current.Default = Items.First(); + Current.Value = Items.First(); } } } From 257934a14415a014d8c5bfd1703064965f70886e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 12:38:30 +0300 Subject: [PATCH 577/961] Revert "Revert ruleset when not applied filters (includes scope change)" This reverts commit 9fa39cd34e867be4d1258b52f427cfb5eb0cbb6b. --- osu.Game/Overlays/RankingsOverlay.cs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 9ddcaa589e..65c9c4d953 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -18,8 +18,6 @@ namespace osu.Game.Overlays protected Bindable Ruleset => Header.Ruleset; protected Bindable Country => Header.Country; - private bool requiresRulesetRevert; - private APIRequest lastRequest; [Resolved] @@ -52,25 +50,6 @@ namespace osu.Game.Overlays }); } - protected override void PopIn() - { - base.PopIn(); - - if (requiresRulesetRevert) - { - Ruleset.SetDefault(); - requiresRulesetRevert = false; - } - } - - protected override void PopOutComplete() - { - base.PopOutComplete(); - - if (Header.Current.Value == default && Country.Value == null) - requiresRulesetRevert = true; - } - protected override void OnTabChanged(RankingsScope tab) { // country filtering is only valid for performance scope. From 6931721864bfba25469f2647caf5b1e1b8b6476b Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 12:39:27 +0300 Subject: [PATCH 578/961] Revert test coverage --- .../Visual/Online/TestSceneRankingsOverlay.cs | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index 74b8cbdfe5..aff510dd95 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -1,16 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using osu.Framework.Allocation; using osu.Game.Overlays; using NUnit.Framework; using osu.Game.Users; using osu.Framework.Bindables; -using osu.Framework.Testing; using osu.Game.Overlays.Rankings; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Taiko; namespace osu.Game.Tests.Visual.Online { @@ -39,44 +35,6 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show", rankingsOverlay.Show); } - [Test] - public void TestRulesetResetsOnNoFilters() - { - AddStep("Set different ruleset", () => rankingsOverlay.ChildrenOfType().Single().SwitchTab(1)); - AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); - AddStep("Hide overlay", () => rankingsOverlay.Hide()); - AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); - - AddStep("Show overlay again", () => rankingsOverlay.Show()); - AddAssert("Ruleset reverted", () => rankingsOverlay.Header.Ruleset.IsDefault); - } - - [Test] - public void TestRulesetDoesntResetOnCountryFilter() - { - AddStep("Set different ruleset", () => rankingsOverlay.ChildrenOfType().Single().SwitchTab(1)); - AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); - AddStep("Set country filter", () => countryBindable.Value = us_country); - AddStep("Hide overlay", () => rankingsOverlay.Hide()); - AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); - - AddStep("Show overlay again", () => rankingsOverlay.Show()); - AddAssert("Ruleset not reverted", () => !rankingsOverlay.Header.Ruleset.IsDefault); - } - - [Test] - public void TestRulesetDoesntResetOnScopeChange() - { - AddStep("Set ruleset to osu!taiko", () => rankingsOverlay.Header.Ruleset.Value = new TaikoRuleset().RulesetInfo); - AddAssert("Ruleset not default", () => !rankingsOverlay.Header.Ruleset.IsDefault); - AddStep("Set different scope", () => scope.Value = RankingsScope.Score); - AddStep("Hide overlay", () => rankingsOverlay.Hide()); - AddUntilStep("Wait for hide", () => !rankingsOverlay.IsPresent); - - AddStep("Show overlay again", () => rankingsOverlay.Show()); - AddAssert("Ruleset not reverted", () => !rankingsOverlay.Header.Ruleset.IsDefault); - } - [Test] public void TestFlagScopeDependency() { From f4b69ceb8ae23ba438fd3230738b3b6e5469e0a1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 12:40:20 +0300 Subject: [PATCH 579/961] Remove unused using embedded in reverted changes --- osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index c46a3966ee..3e707fc091 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics.UserInterface; using osu.Game.Beatmaps; using osu.Game.Rulesets; using System.Linq; -using osu.Framework.Allocation; namespace osu.Game.Overlays.BeatmapSet { From d3958eb3fbc518f7fc2e273e19da90924b22e897 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 13:23:57 +0300 Subject: [PATCH 580/961] Revert initial ruleset value logic --- .../BeatmapSet/BeatmapRulesetSelector.cs | 2 -- osu.Game/Overlays/OverlayRulesetSelector.cs | 14 -------------- osu.Game/Rulesets/RulesetSelector.cs | 17 ----------------- 3 files changed, 33 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs index 3e707fc091..005d21726b 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetSelector.cs @@ -11,8 +11,6 @@ namespace osu.Game.Overlays.BeatmapSet { public class BeatmapRulesetSelector : OverlayRulesetSelector { - protected override bool SelectInitialRuleset => false; - private readonly Bindable beatmapSet = new Bindable(); public BeatmapSetInfo BeatmapSet diff --git a/osu.Game/Overlays/OverlayRulesetSelector.cs b/osu.Game/Overlays/OverlayRulesetSelector.cs index 60b16abd48..8c44157f78 100644 --- a/osu.Game/Overlays/OverlayRulesetSelector.cs +++ b/osu.Game/Overlays/OverlayRulesetSelector.cs @@ -1,11 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Rulesets; using osuTK; @@ -18,18 +16,6 @@ namespace osu.Game.Overlays AutoSizeAxes = Axes.Both; } - [BackgroundDependencyLoader] - private void load(RulesetStore store, IAPIProvider api) - { - if (SelectInitialRuleset) - { - var preferredRuleset = store.GetRuleset(api.LocalUser.Value.PlayMode); - - if (preferredRuleset != null) - Current.Value = preferredRuleset; - } - } - protected override TabItem CreateTabItem(RulesetInfo value) => new OverlayRulesetTabItem(value); protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer diff --git a/osu.Game/Rulesets/RulesetSelector.cs b/osu.Game/Rulesets/RulesetSelector.cs index e5d39fa144..8e6ec556d2 100644 --- a/osu.Game/Rulesets/RulesetSelector.cs +++ b/osu.Game/Rulesets/RulesetSelector.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.Graphics.UserInterface; using osu.Framework.Allocation; @@ -14,27 +13,11 @@ namespace osu.Game.Rulesets protected override Dropdown CreateDropdown() => null; - protected virtual bool SelectInitialRuleset => true; - - protected RulesetSelector() - { - SelectFirstTabByDefault = false; - } - [BackgroundDependencyLoader] private void load() { foreach (var r in Rulesets.AvailableRulesets) AddItem(r); - - if (SelectInitialRuleset) - { - // This is supposed to be an implicit process in the base class, but the problem is that it happens in LoadComplete. - // That can become an issue with overlays that require access to the initial ruleset value - // before the ruleset selectors reached a LoadComplete state. - // (e.g. displaying RankingsOverlay for the first time). - Current.Value = Items.First(); - } } } } From f8a7e0bdb6bd21af2e83c483e1bff07a33da2a27 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 13:50:39 +0300 Subject: [PATCH 581/961] Update rankings overlay ruleset bindable with parent on initial display --- osu.Game/Overlays/RankingsOverlay.cs | 32 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/RankingsOverlay.cs b/osu.Game/Overlays/RankingsOverlay.cs index 65c9c4d953..b8bdef925e 100644 --- a/osu.Game/Overlays/RankingsOverlay.cs +++ b/osu.Game/Overlays/RankingsOverlay.cs @@ -15,7 +15,6 @@ namespace osu.Game.Overlays { public class RankingsOverlay : TabbableOnlineOverlay { - protected Bindable Ruleset => Header.Ruleset; protected Bindable Country => Header.Country; private APIRequest lastRequest; @@ -23,6 +22,12 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } + [Resolved] + private IBindable parentRuleset { get; set; } + + [Cached] + private readonly Bindable ruleset = new Bindable(); + public RankingsOverlay() : base(OverlayColourScheme.Green) { @@ -32,6 +37,8 @@ namespace osu.Game.Overlays { base.LoadComplete(); + Header.Ruleset.BindTo(ruleset); + Country.BindValueChanged(_ => { // if a country is requested, force performance scope. @@ -41,7 +48,7 @@ namespace osu.Game.Overlays Scheduler.AddOnce(triggerTabChanged); }); - Ruleset.BindValueChanged(_ => + ruleset.BindValueChanged(_ => { if (Header.Current.Value == RankingsScope.Spotlights) return; @@ -50,6 +57,19 @@ namespace osu.Game.Overlays }); } + private bool requiresRulesetUpdate = true; + + protected override void PopIn() + { + if (requiresRulesetUpdate) + { + ruleset.Value = parentRuleset.Value; + requiresRulesetUpdate = false; + } + + base.PopIn(); + } + protected override void OnTabChanged(RankingsScope tab) { // country filtering is only valid for performance scope. @@ -81,7 +101,7 @@ namespace osu.Game.Overlays { LoadDisplay(new SpotlightsLayout { - Ruleset = { BindTarget = Ruleset } + Ruleset = { BindTarget = ruleset } }); return; } @@ -106,13 +126,13 @@ namespace osu.Game.Overlays switch (Header.Current.Value) { case RankingsScope.Performance: - return new GetUserRankingsRequest(Ruleset.Value, country: Country.Value?.FlagName); + return new GetUserRankingsRequest(ruleset.Value, country: Country.Value?.FlagName); case RankingsScope.Country: - return new GetCountryRankingsRequest(Ruleset.Value); + return new GetCountryRankingsRequest(ruleset.Value); case RankingsScope.Score: - return new GetUserRankingsRequest(Ruleset.Value, UserRankingsType.Score); + return new GetUserRankingsRequest(ruleset.Value, UserRankingsType.Score); } return null; From e33c3fcdbf9940e864ebdd53f70f812021b0e76f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 13:53:03 +0300 Subject: [PATCH 582/961] Add test coverage for new changes --- .../Visual/Online/TestSceneRankingsOverlay.cs | 36 +++++++++---------- .../TestSceneOverlayRulesetSelector.cs | 22 ------------ 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index aff510dd95..342ae76377 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -1,12 +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 osu.Framework.Allocation; -using osu.Game.Overlays; using NUnit.Framework; -using osu.Game.Users; using osu.Framework.Bindables; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays; using osu.Game.Overlays.Rankings; +using osu.Game.Rulesets.Catch; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Online { @@ -14,25 +15,20 @@ namespace osu.Game.Tests.Visual.Online { protected override bool UseOnlineAPI => true; - [Cached(typeof(RankingsOverlay))] - private readonly RankingsOverlay rankingsOverlay; + private TestRankingsOverlay rankingsOverlay; private readonly Bindable countryBindable = new Bindable(); private readonly Bindable scope = new Bindable(); - public TestSceneRankingsOverlay() - { - Add(rankingsOverlay = new TestRankingsOverlay - { - Country = { BindTarget = countryBindable }, - Header = { Current = { BindTarget = scope } }, - }); - } + [SetUp] + public void SetUp() => Schedule(loadRankingsOverlay); [Test] - public void TestShow() + public void TestParentRulesetCopiedOnInitialShow() { - AddStep("Show", rankingsOverlay.Show); + AddStep("set ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo); + AddStep("reload rankings overlay", loadRankingsOverlay); + AddAssert("catch ruleset selected", () => Ruleset.Value.Equals(new CatchRuleset().RulesetInfo)); } [Test] @@ -50,10 +46,14 @@ namespace osu.Game.Tests.Visual.Online AddStep("Show US", () => rankingsOverlay.ShowCountry(us_country)); } - [Test] - public void TestHide() + private void loadRankingsOverlay() { - AddStep("Hide", rankingsOverlay.Hide); + Child = rankingsOverlay = new TestRankingsOverlay + { + Country = { BindTarget = countryBindable }, + Header = { Current = { BindTarget = scope } }, + State = { Value = Visibility.Visible }, + }; } private static readonly Country us_country = new Country diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs index de55914fa8..f4fa41a3b7 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayRulesetSelector.cs @@ -70,27 +70,5 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("Select catch", () => ruleset.Value = new CatchRuleset().RulesetInfo); AddAssert("Check catch selected", () => selector.Current.Value.Equals(new CatchRuleset().RulesetInfo)); } - - [Test] - public void TestUserPreferredRuleset() - { - OverlayRulesetSelector localSelector = null; - - AddStep("Set osu! preferred ruleset", () => API.LocalUser.Value.PlayMode = OsuRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); - AddAssert("Check osu! selected", () => localSelector.Current.Value.Equals(new OsuRuleset().RulesetInfo)); - - AddStep("Set osu!taiko preferred ruleset", () => API.LocalUser.Value.PlayMode = TaikoRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); - AddAssert("Check osu!taiko selected", () => localSelector.Current.Value.Equals(new TaikoRuleset().RulesetInfo)); - - AddStep("Set osu!catch preferred ruleset", () => API.LocalUser.Value.PlayMode = CatchRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); - AddAssert("Check osu!catch selected", () => localSelector.Current.Value.Equals(new CatchRuleset().RulesetInfo)); - - AddStep("Set osu!mania preferred ruleset", () => API.LocalUser.Value.PlayMode = ManiaRuleset.SHORT_NAME); - AddStep("load overlay ruleset selector", () => Child = new ColourProvidedContainer(OverlayColourScheme.Red, localSelector = new OverlayRulesetSelector())); - AddAssert("Check osu!mania selected", () => localSelector.Current.Value.Equals(new ManiaRuleset().RulesetInfo)); - } } } From fed0e15cea3f331722ece7b1a0f805eef16a5ad9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 20:23:46 +0900 Subject: [PATCH 583/961] Fix typo in `ArchiveModelManager` --- osu.Game/Database/ArchiveModelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Database/ArchiveModelManager.cs b/osu.Game/Database/ArchiveModelManager.cs index 87bf54f981..ddd2bc5d1e 100644 --- a/osu.Game/Database/ArchiveModelManager.cs +++ b/osu.Game/Database/ArchiveModelManager.cs @@ -806,7 +806,7 @@ namespace osu.Game.Database protected TModel CheckForExisting(TModel model) => model.Hash == null ? null : ModelStore.ConsumableItems.FirstOrDefault(b => b.Hash == model.Hash); /// - /// Whether inport can be skipped after finding an existing import early in the process. + /// Whether import can be skipped after finding an existing import early in the process. /// Only valid when is not overridden. /// /// The existing model. From 7b3f7cc7c1e4534afdd96cf2c97499b418e4a1c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 20:24:00 +0900 Subject: [PATCH 584/961] Change skin import to also include directory names in the skin name where appropriate --- osu.Game/Skinning/SkinManager.cs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 0f805990b9..0aa1c62d04 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -136,18 +136,19 @@ namespace osu.Game.Skinning protected override string ComputeHash(SkinInfo item, ArchiveReader reader = null) { - // we need to populate early to create a hash based off skin.ini contents - if (item.Name?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true) - populateMetadata(item, GetSkin(item)); + var instance = GetSkin(item); - if (item.Creator != null && item.Creator != unknown_creator_string) + // in the case the skin has a skin.ini file, we are going to create a hash based on that. + // we don't want to do this in the case we don't have a skin.ini, as it would match only on the filename portion, + // causing potentially unique skin imports to be considered as a duplicate. + if (!string.IsNullOrEmpty(instance.Configuration.SkinInfo.Name)) { - // this is the optimal way to hash legacy skins, but will need to be reconsidered when we move forward with skin implementation. - // likely, the skin should expose a real version (ie. the version of the skin, not the skin.ini version it's targeting). + // we need to populate early to create a hash based off skin.ini contents + populateMetadata(item, instance, reader?.Name); + return item.ToString().ComputeSHA2Hash(); } - // if there was no creator, the ToString above would give the filename, which alone isn't really enough to base any decisions on. return base.ComputeHash(item, reader); } @@ -157,13 +158,12 @@ namespace osu.Game.Skinning model.InstantiationInfo ??= instance.GetType().GetInvariantInstantiationInfo(); - if (model.Name?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true) - populateMetadata(model, instance); + populateMetadata(model, instance, archive?.Name); return Task.CompletedTask; } - private void populateMetadata(SkinInfo item, Skin instance) + private void populateMetadata(SkinInfo item, Skin instance, string archiveName) { if (!string.IsNullOrEmpty(instance.Configuration.SkinInfo.Name)) { @@ -175,6 +175,13 @@ namespace osu.Game.Skinning item.Name = item.Name.Replace(".osk", "", StringComparison.OrdinalIgnoreCase); item.Creator ??= unknown_creator_string; } + + // generally when importing from a folder, the ".osk" extension will not be present. + // if we ever need a more reliable method of determining this, the type of `ArchiveReader` can be checked. + bool isArchiveImport = archiveName?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true; + + if (archiveName != null && !isArchiveImport && archiveName != item.Name) + item.Name = $"{item.Name} ({archiveName})"; } /// From 0cbe95d6611c0a6921c6be892f9db02af3735bc4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 20:25:46 +0900 Subject: [PATCH 585/961] Add test coverage of different folder names with same skin.ini --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 36 +++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index bab8dfc983..0329ca11e2 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -138,16 +138,38 @@ namespace osu.Game.Tests.Skins.IO } } - private MemoryStream createOsk(string name, string author) + [Test] + public async Task TestSameMetadataNameDifferentFolderName() + { + using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(ImportSkinTest))) + { + try + { + var osu = LoadOsuIntoHost(host); + + var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 1")); + + var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 2")); + + Assert.That(imported2.Hash, Is.Not.EqualTo(imported.Hash)); + } + finally + { + host.Exit(); + } + } + } + + private MemoryStream createOsk(string name, string author, bool makeUnique = true) { var zipStream = new MemoryStream(); using var zip = ZipArchive.Create(); - zip.AddEntry("skin.ini", generateSkinIni(name, author)); + zip.AddEntry("skin.ini", generateSkinIni(name, author, makeUnique)); zip.SaveTo(zipStream); return zipStream; } - private MemoryStream generateSkinIni(string name, string author) + private MemoryStream generateSkinIni(string name, string author, bool makeUnique = true) { var stream = new MemoryStream(); var writer = new StreamWriter(stream); @@ -155,8 +177,12 @@ namespace osu.Game.Tests.Skins.IO writer.WriteLine("[General]"); writer.WriteLine($"Name: {name}"); writer.WriteLine($"Author: {author}"); - writer.WriteLine(); - writer.WriteLine($"# unique {Guid.NewGuid()}"); + + if (makeUnique) + { + writer.WriteLine(); + writer.WriteLine($"# unique {Guid.NewGuid()}"); + } writer.Flush(); From a2484692b3a29cc71c383e3f8b43f250d43c6393 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 23 Aug 2021 20:37:19 +0900 Subject: [PATCH 586/961] Change brackets to square --- osu.Game.Tests/Skins/IO/ImportSkinTest.cs | 4 ++++ osu.Game/Skinning/SkinManager.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 0329ca11e2..7a9fc20426 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -148,8 +148,12 @@ namespace osu.Game.Tests.Skins.IO var osu = LoadOsuIntoHost(host); var imported = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 1")); + Assert.That(imported.Name, Is.EqualTo("name 1 [my custom skin 1]")); + Assert.That(imported.Creator, Is.EqualTo("author 1")); var imported2 = await loadSkinIntoOsu(osu, new ZipArchiveReader(createOsk("name 1", "author 1", false), "my custom skin 2")); + Assert.That(imported2.Name, Is.EqualTo("name 1 [my custom skin 2]")); + Assert.That(imported2.Creator, Is.EqualTo("author 1")); Assert.That(imported2.Hash, Is.Not.EqualTo(imported.Hash)); } diff --git a/osu.Game/Skinning/SkinManager.cs b/osu.Game/Skinning/SkinManager.cs index 0aa1c62d04..edeb17cbad 100644 --- a/osu.Game/Skinning/SkinManager.cs +++ b/osu.Game/Skinning/SkinManager.cs @@ -181,7 +181,7 @@ namespace osu.Game.Skinning bool isArchiveImport = archiveName?.Contains(".osk", StringComparison.OrdinalIgnoreCase) == true; if (archiveName != null && !isArchiveImport && archiveName != item.Name) - item.Name = $"{item.Name} ({archiveName})"; + item.Name = $"{item.Name} [{archiveName}]"; } /// From bd42d7aada02c787cd3d32396decb36f836c2683 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 18:01:01 +0300 Subject: [PATCH 587/961] Hide popover on file selection --- .../Edit/Setup/FileChooserLabelledTextBox.cs | 7 +-- .../Screens/Edit/Setup/ResourcesSection.cs | 59 ++++--------------- 2 files changed, 14 insertions(+), 52 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs index e68e581942..fd43349793 100644 --- a/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs +++ b/osu.Game/Screens/Edit/Setup/FileChooserLabelledTextBox.cs @@ -31,11 +31,6 @@ namespace osu.Game.Screens.Edit.Setup public IEnumerable HandledExtensions => handledExtensions; - /// - /// The target container to display the file chooser in. - /// - public Container Target; - private readonly Bindable currentFile = new Bindable(); [Resolved] @@ -72,7 +67,7 @@ namespace osu.Game.Screens.Edit.Setup if (file.NewValue == null) return; - Target.Clear(); + this.HidePopover(); Current.Value = file.NewValue.FullName; } diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs index ba22c82ecc..8e739a786f 100644 --- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs +++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs @@ -6,7 +6,6 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; @@ -39,62 +38,30 @@ namespace osu.Game.Screens.Edit.Setup [BackgroundDependencyLoader] private void load() { - Container audioTrackFileChooserContainer = createFileChooserContainer(); - Container backgroundFileChooserContainer = createFileChooserContainer(); - Children = new Drawable[] { - new FillFlowContainer + backgroundTextBox = new FileChooserLabelledTextBox(".jpg", ".jpeg", ".png") { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - backgroundTextBox = new FileChooserLabelledTextBox(".jpg", ".jpeg", ".png") - { - Label = "Background", - FixedLabelWidth = LABEL_WIDTH, - PlaceholderText = "Click to select a background image", - Current = { Value = working.Value.Metadata.BackgroundFile }, - Target = backgroundFileChooserContainer, - TabbableContentContainer = this - }, - backgroundFileChooserContainer, - } + Label = "Background", + FixedLabelWidth = LABEL_WIDTH, + PlaceholderText = "Click to select a background image", + Current = { Value = working.Value.Metadata.BackgroundFile }, + TabbableContentContainer = this }, - new FillFlowContainer + audioTrackTextBox = new FileChooserLabelledTextBox(".mp3", ".ogg") { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - audioTrackTextBox = new FileChooserLabelledTextBox(".mp3", ".ogg") - { - Label = "Audio Track", - FixedLabelWidth = LABEL_WIDTH, - PlaceholderText = "Click to select a track", - Current = { Value = working.Value.Metadata.AudioFile }, - Target = audioTrackFileChooserContainer, - TabbableContentContainer = this - }, - audioTrackFileChooserContainer, - } - } + Label = "Audio Track", + FixedLabelWidth = LABEL_WIDTH, + PlaceholderText = "Click to select a track", + Current = { Value = working.Value.Metadata.AudioFile }, + TabbableContentContainer = this + }, }; backgroundTextBox.Current.BindValueChanged(backgroundChanged); audioTrackTextBox.Current.BindValueChanged(audioTrackChanged); } - private static Container createFileChooserContainer() => - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }; - public bool ChangeBackgroundImage(string path) { var info = new FileInfo(path); From 9a507ed2736c4c79d7382024e535bcec78cda5b5 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Mon, 23 Aug 2021 16:27:29 +0100 Subject: [PATCH 588/961] update selected section on children count change --- osu.Game/Graphics/Containers/SectionsContainer.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 76492cab55..00c55bdd57 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -202,6 +202,8 @@ namespace osu.Game.Graphics.Containers }); } + private int lastKnownChildrenCount = 0; + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -220,10 +222,12 @@ namespace osu.Game.Graphics.Containers } float currentScroll = scrollContainer.Current; + var presentChildren = Children.Where(c => c.IsPresent); - if (currentScroll != lastKnownScroll) + if (currentScroll != lastKnownScroll || presentChildren.Count() != lastKnownChildrenCount) { lastKnownScroll = currentScroll; + lastKnownChildrenCount = presentChildren.Count(); // reset last clicked section because user started scrolling themselves if (scrollContainer.UserScrolling) @@ -249,8 +253,6 @@ namespace osu.Game.Graphics.Containers float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection; - var presentChildren = Children.Where(c => c.IsPresent); - if (lastClickedSection != null) SelectedSection.Value = lastClickedSection; else if (Precision.AlmostBigger(0, scrollContainer.Current)) From 20222f09c463a8a443b9def3c5b207f478b20d69 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Mon, 23 Aug 2021 16:55:31 +0100 Subject: [PATCH 589/961] oops redundant default value --- osu.Game/Graphics/Containers/SectionsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index 00c55bdd57..cd6d0a9432 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -202,7 +202,7 @@ namespace osu.Game.Graphics.Containers }); } - private int lastKnownChildrenCount = 0; + private int lastKnownChildrenCount; protected override void UpdateAfterChildren() { From 6bea744e345696926b0e0e4159b3796fa1cf6dbc Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Mon, 23 Aug 2021 17:13:25 +0100 Subject: [PATCH 590/961] invalidate scroll position --- osu.Game/Graphics/Containers/SectionsContainer.cs | 8 +++----- osu.Game/Overlays/SettingsPanel.cs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/SectionsContainer.cs b/osu.Game/Graphics/Containers/SectionsContainer.cs index cd6d0a9432..76492cab55 100644 --- a/osu.Game/Graphics/Containers/SectionsContainer.cs +++ b/osu.Game/Graphics/Containers/SectionsContainer.cs @@ -202,8 +202,6 @@ namespace osu.Game.Graphics.Containers }); } - private int lastKnownChildrenCount; - protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -222,12 +220,10 @@ namespace osu.Game.Graphics.Containers } float currentScroll = scrollContainer.Current; - var presentChildren = Children.Where(c => c.IsPresent); - if (currentScroll != lastKnownScroll || presentChildren.Count() != lastKnownChildrenCount) + if (currentScroll != lastKnownScroll) { lastKnownScroll = currentScroll; - lastKnownChildrenCount = presentChildren.Count(); // reset last clicked section because user started scrolling themselves if (scrollContainer.UserScrolling) @@ -253,6 +249,8 @@ namespace osu.Game.Graphics.Containers float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection; + var presentChildren = Children.Where(c => c.IsPresent); + if (lastClickedSection != null) SelectedSection.Value = lastClickedSection; else if (Precision.AlmostBigger(0, scrollContainer.Current)) diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index e4e76592d8..5589786169 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -211,7 +211,7 @@ namespace osu.Game.Overlays loading.Hide(); - searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchContainer.SearchTerm = term.NewValue, true); + searchTextBox.Current.BindValueChanged(term => SectionsContainer.SearchTerm = term.NewValue, true); searchTextBox.TakeFocus(); loadSidebarButtons(); From 9d807656f26e6bc3882d38630b83269da670c1ff Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 23 Aug 2021 21:08:59 +0300 Subject: [PATCH 591/961] Add more complete test coverage of decoupling --- .../Visual/Online/TestSceneRankingsOverlay.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs index 342ae76377..027f17fff4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsOverlay.cs @@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers; using osu.Game.Overlays; using osu.Game.Overlays.Rankings; using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; using osu.Game.Users; namespace osu.Game.Tests.Visual.Online @@ -24,11 +26,20 @@ namespace osu.Game.Tests.Visual.Online public void SetUp() => Schedule(loadRankingsOverlay); [Test] - public void TestParentRulesetCopiedOnInitialShow() + public void TestParentRulesetDecoupledAfterInitialShow() { - AddStep("set ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo); + AddStep("enable global ruleset", () => Ruleset.Disabled = false); + AddStep("set global ruleset to osu!catch", () => Ruleset.Value = new CatchRuleset().RulesetInfo); AddStep("reload rankings overlay", loadRankingsOverlay); - AddAssert("catch ruleset selected", () => Ruleset.Value.Equals(new CatchRuleset().RulesetInfo)); + AddAssert("rankings ruleset set to osu!catch", () => rankingsOverlay.Header.Ruleset.Value.ShortName == CatchRuleset.SHORT_NAME); + + AddStep("set global ruleset to osu!", () => Ruleset.Value = new OsuRuleset().RulesetInfo); + AddAssert("rankings ruleset still osu!catch", () => rankingsOverlay.Header.Ruleset.Value.ShortName == CatchRuleset.SHORT_NAME); + + AddStep("disable global ruleset", () => Ruleset.Disabled = true); + AddAssert("rankings ruleset still enabled", () => rankingsOverlay.Header.Ruleset.Disabled == false); + AddStep("set rankings ruleset to osu!mania", () => rankingsOverlay.Header.Ruleset.Value = new ManiaRuleset().RulesetInfo); + AddAssert("rankings ruleset set to osu!mania", () => rankingsOverlay.Header.Ruleset.Value.ShortName == ManiaRuleset.SHORT_NAME); } [Test] From 6e3d05c7ce5c42cd932ddab403c6f1654caffe2d Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Tue, 24 Aug 2021 09:42:53 +0800 Subject: [PATCH 592/961] Display an icon to signify incompatibility instead of a red tint --- osu.Game/Overlays/Mods/ModButton.cs | 43 +++++++++++++++++------------ 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 359d1a7981..f4233c65cb 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -33,6 +33,7 @@ namespace osu.Game.Overlays.Mods private ModIcon backgroundIcon; private readonly SpriteText text; private readonly Container iconsContainer; + private readonly SpriteIcon incompatibleIcon; /// /// Fired when the selection changes. @@ -243,28 +244,25 @@ namespace osu.Game.Overlays.Mods backgroundIcon.Mod = foregroundIcon.Mod; foregroundIcon.Mod = mod; text.Text = mod.Name; - updateColour(mod); + Colour = mod.HasImplementation ? Color4.White : Color4.Gray; + updateCompatibility(mod); } - private Colour4 lightRed; - private Colour4 darkRed; - - private void updateColour(Mod mod) + private void updateCompatibility(Mod mod) { - var baseColour = mod.HasImplementation ? Color4.White : Color4.Gray; - if (globalSelectedMods != null) { if (!globalSelectedMods.Value.Contains(mod)) { if (!ModUtils.CheckCompatibleSet(globalSelectedMods.Value.Concat(new[] { mod }))) { - baseColour = mod.HasImplementation ? lightRed : darkRed; + incompatibleIcon.FadeIn(); + return; } } } - Colour = baseColour; + incompatibleIcon.FadeOut(); } private void createIcons() @@ -312,11 +310,24 @@ namespace osu.Game.Overlays.Mods { scaleContainer = new Container { - Child = iconsContainer = new Container + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, + iconsContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + }, + incompatibleIcon = new SpriteIcon + { + Origin = Anchor.BottomRight, + Anchor = Anchor.BottomRight, + Icon = FontAwesome.Solid.Ban, + Colour = Color4.Red, + Size = new Vector2(30), + Shadow = true, + Alpha = 0 + } }, RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, @@ -338,11 +349,9 @@ namespace osu.Game.Overlays.Mods } [BackgroundDependencyLoader] - private void load(OsuColour colour) + private void load() { - lightRed = colour.RedLight; - darkRed = colour.RedDark; - globalSelectedMods.BindValueChanged(_ => updateColour(SelectedMod ?? Mods.FirstOrDefault()), true); + globalSelectedMods.BindValueChanged(_ => updateCompatibility(SelectedMod ?? Mods.FirstOrDefault()), true); } public ITooltip GetCustomTooltip() => new ModButtonTooltip(); From b8fe03b77f8912bf1f6cf9b65548194a54e4ad0b Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Tue, 24 Aug 2021 09:50:09 +0800 Subject: [PATCH 593/961] Use `Mod.Equals` for comparison --- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 1b889281f0..666ed07e28 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -80,16 +80,16 @@ namespace osu.Game.Overlays.Mods protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); - private string lastMod; + private Mod lastMod; public bool SetContent(object content) { if (!(content is Mod mod)) return false; - if (mod.Acronym == lastMod) return true; + if (mod.Equals(lastMod)) return true; - lastMod = mod.Acronym; + lastMod = mod; descriptionText.Text = mod.Description; From c2974cfc65b1b74697729776dd533a621d84f33b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 13:20:01 +0900 Subject: [PATCH 594/961] Add full multiplayer gameplay flow test --- osu.Game.Tests/Resources/TestResources.cs | 2 ++ .../Multiplayer/TestSceneMultiplayer.cs | 36 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs index cef0532f9d..7170a76b8b 100644 --- a/osu.Game.Tests/Resources/TestResources.cs +++ b/osu.Game.Tests/Resources/TestResources.cs @@ -9,6 +9,8 @@ namespace osu.Game.Tests.Resources { public static class TestResources { + public const double QUICK_BEATMAP_LENGTH = 10000; + public static DllResourceStore GetStore() => new DllResourceStore(typeof(TestResources).Assembly); public static Stream OpenResource(string name) => GetStore().GetStream($"Resources/{name}"); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 6c1aed71e6..7a3507d944 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -28,6 +28,8 @@ using osu.Game.Screens.OnlinePlay.Lounge.Components; using osu.Game.Screens.OnlinePlay.Match; using osu.Game.Screens.OnlinePlay.Multiplayer; using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Screens.Play; +using osu.Game.Screens.Ranking; using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK.Input; @@ -430,6 +432,40 @@ namespace osu.Game.Tests.Visual.Multiplayer } } + [Test] + public void TestGameplayFlow() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddRepeatStep("click spectate button", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }, 2); + + AddUntilStep("wait for player", () => Stack.CurrentScreen is Player); + + // Gameplay runs in real-time, so we need to incrementally check if gameplay has finished in order to not time out. + for (double i = 1000; i < TestResources.QUICK_BEATMAP_LENGTH; i += 1000) + { + var time = i; + AddUntilStep($"wait for time > {i}", () => this.ChildrenOfType().SingleOrDefault()?.GameplayClock.CurrentTime > time); + } + + AddUntilStep("wait for results", () => Stack.CurrentScreen is ResultsScreen); + } + private void createRoom(Func room) { AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); From df170afbc433b3ea8faeb9afe2ec5ac35f16e34a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 13:22:06 +0900 Subject: [PATCH 595/961] Fix multiplayer crashing when entering gameplay --- .../Multiplayer/TestSceneGameplayChatDisplay.cs | 2 +- .../Visual/Multiplayer/TestSceneMultiplayerPlayer.cs | 2 +- .../OnlinePlay/Match/Components/MatchChatDisplay.cs | 12 ++++++------ .../OnlinePlay/Multiplayer/GameplayChatDisplay.cs | 5 +++-- .../Multiplayer/MultiplayerMatchSubScreen.cs | 4 ++-- .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 7 ++++--- .../Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs | 4 ++-- .../OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 4 ++-- osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 10 ++++++---- 9 files changed, 27 insertions(+), 23 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs index eadfc9b279..a3a1cacb0d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneGameplayChatDisplay.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { base.SetUpSteps(); - AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay + AddStep("load chat display", () => Child = chatDisplay = new GameplayChatDisplay(SelectedRoom.Value) { Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs index 80da7a7e5e..a1543f99e1 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlayer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("initialise gameplay", () => { - Stack.Push(player = new MultiplayerPlayer(Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray())); + Stack.Push(player = new MultiplayerPlayer(Client.APIRoom, Client.CurrentMatchPlayingItem.Value, Client.Room?.Users.ToArray())); }); } diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index 5f960c1b5c..05a3546cec 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -10,21 +10,21 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchChatDisplay : StandAloneChatDisplay { - [Resolved(typeof(Room), nameof(Room.RoomID))] - private Bindable roomId { get; set; } - - [Resolved(typeof(Room), nameof(Room.ChannelId))] - private Bindable channelId { get; set; } + private readonly IBindable roomId = new Bindable(); + private readonly IBindable channelId = new Bindable(); [Resolved(CanBeNull = true)] private ChannelManager channelManager { get; set; } private readonly bool leaveChannelOnDispose; - public MatchChatDisplay(bool leaveChannelOnDispose = true) + public MatchChatDisplay(Room room, bool leaveChannelOnDispose = true) : base(true) { this.leaveChannelOnDispose = leaveChannelOnDispose; + + roomId.BindTo(room.RoomID); + channelId.BindTo(room.ChannelId); } protected override void LoadComplete() diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs index 9fe41842f3..3af72fa25a 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/GameplayChatDisplay.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Input.Bindings; +using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Play; @@ -29,8 +30,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer public override bool PropagateNonPositionalInputSubTree => true; - public GameplayChatDisplay() - : base(leaveChannelOnDispose: false) + public GameplayChatDisplay(Room room) + : base(room, leaveChannelOnDispose: false) { RelativeSizeAxes = Axes.X; diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 06e60903aa..fb18e7a31f 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer }, }, new Drawable[] { new OverlinedHeader("Chat") { Margin = new MarginPadding { Vertical = 5 }, }, }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + new Drawable[] { new MatchChatDisplay(Room) { RelativeSizeAxes = Axes.Both } } }, RowDimensions = new[] { @@ -395,7 +395,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return new MultiSpectatorScreen(users.Take(PlayerGrid.MAX_PLAYERS).ToArray()); default: - return new PlayerLoader(() => new MultiplayerPlayer(SelectedItem.Value, users)); + return new PlayerLoader(() => new MultiplayerPlayer(Room, SelectedItem.Value, users)); } } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 24657943d7..4c26feb067 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -45,10 +45,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// /// Construct a multiplayer player. /// + /// The room. /// The playlist item to be played. /// The users which are participating in this game. - public MultiplayerPlayer(PlaylistItem playlistItem, MultiplayerRoomUser[] users) - : base(playlistItem, new PlayerConfiguration + public MultiplayerPlayer(Room room, PlaylistItem playlistItem, MultiplayerRoomUser[] users) + : base(room, playlistItem, new PlayerConfiguration { AllowPause = false, AllowRestart = false, @@ -92,7 +93,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer } }); - LoadComponentAsync(new GameplayChatDisplay + LoadComponentAsync(new GameplayChatDisplay(Room) { Expanded = { BindTarget = HUDOverlay.ShowHud }, }, chat => leaderboardFlow.Insert(2, chat)); diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index 567ea6b988..c441728bb6 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -20,8 +20,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists { public Action Exited; - public PlaylistsPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) - : base(playlistItem, configuration) + public PlaylistsPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null) + : base(room, playlistItem, configuration) { } diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 98fed3b467..a9ce9c52c4 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -158,7 +158,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists }, new Drawable[] { leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }, }, new Drawable[] { new OverlinedHeader("Chat"), }, - new Drawable[] { new MatchChatDisplay { RelativeSizeAxes = Axes.Both } } + new Drawable[] { new MatchChatDisplay(Room) { RelativeSizeAxes = Axes.Both } } }, RowDimensions = new[] { @@ -199,7 +199,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists Logger.Log($"Polling adjusted (selection: {selectionPollingComponent.TimeBetweenPolls.Value})"); } - protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(SelectedItem.Value) + protected override Screen CreateGameplayScreen() => new PlayerLoader(() => new PlaylistsPlayer(Room, SelectedItem.Value) { Exited = () => leaderboard.RefreshScores() }); diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index 7ba12f5db6..593b67a7b0 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.API; using osu.Game.Online.Rooms; @@ -14,15 +13,18 @@ namespace osu.Game.Screens.Play /// public abstract class RoomSubmittingPlayer : SubmittingPlayer { - [Resolved(typeof(Room), nameof(Room.RoomID))] - protected Bindable RoomId { get; private set; } + protected readonly IBindable RoomId = new Bindable(); protected readonly PlaylistItem PlaylistItem; + protected readonly Room Room; - protected RoomSubmittingPlayer(PlaylistItem playlistItem, PlayerConfiguration configuration = null) + protected RoomSubmittingPlayer(Room room, PlaylistItem playlistItem, PlayerConfiguration configuration = null) : base(configuration) { + Room = room; PlaylistItem = playlistItem; + + RoomId.BindTo(room.RoomID); } protected override APIRequest CreateTokenRequest() From de0de451fe4ce6de0a4ee407ee579297fc408586 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 13:29:19 +0900 Subject: [PATCH 596/961] Refactor to remove resolved dependency --- .../Multiplayer/Match/BeatmapSelectionControl.cs | 2 +- .../OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs | 4 +++- .../OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs | 2 +- osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs | 8 ++++---- .../OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs | 2 +- .../Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs | 5 +++++ 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs index 2e94e51385..6f1817a77c 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/BeatmapSelectionControl.cs @@ -52,7 +52,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match Action = () => { if (matchSubScreen.IsCurrentScreen()) - matchSubScreen.Push(new MultiplayerMatchSongSelect()); + matchSubScreen.Push(new MultiplayerMatchSongSelect(matchSubScreen.Room)); }, Alpha = 0 } diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 3733b85a5e..ad4bb90551 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -24,9 +24,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer /// /// Construct a new instance of multiplayer song select. /// + /// The room. /// An optional initial beatmap selection to perform. /// An optional initial ruleset selection to perform. - public MultiplayerMatchSongSelect(WorkingBeatmap beatmap = null, RulesetInfo ruleset = null) + public MultiplayerMatchSongSelect(Room room, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null) + : base(room) { if (beatmap != null || ruleset != null) { diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs index 06e60903aa..c0c6f183fb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSubScreen.cs @@ -412,7 +412,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer return; } - this.Push(new MultiplayerMatchSongSelect(beatmap, ruleset)); + this.Push(new MultiplayerMatchSongSelect(Room, beatmap, ruleset)); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index de1b990573..1a063fd6c6 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -33,9 +33,6 @@ namespace osu.Game.Screens.OnlinePlay [Resolved(typeof(Room), nameof(Room.Playlist))] protected BindableList Playlist { get; private set; } - [Resolved] - private Room room { get; set; } - protected override UserActivity InitialActivity => new UserActivity.InLobby(room); protected readonly Bindable> FreeMods = new Bindable>(Array.Empty()); @@ -45,14 +42,17 @@ namespace osu.Game.Screens.OnlinePlay private IBindable selectedItem { get; set; } private readonly FreeModSelectOverlay freeModSelectOverlay; + private readonly Room room; private WorkingBeatmap initialBeatmap; private RulesetInfo initialRuleset; private IReadOnlyList initialMods; private bool itemSelected; - protected OnlinePlaySongSelect() + protected OnlinePlaySongSelect(Room room) { + this.room = room; + Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; freeModSelectOverlay = new FreeModSelectOverlay diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs index 98fed3b467..63a46433aa 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsRoomSubScreen.cs @@ -189,7 +189,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists EditPlaylist = () => { if (this.IsCurrentScreen()) - this.Push(new PlaylistsSongSelect()); + this.Push(new PlaylistsSongSelect(Room)); }, }; diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs index 076fa77336..03c95ec060 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsSongSelect.cs @@ -16,6 +16,11 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved] private BeatmapManager beatmaps { get; set; } + public PlaylistsSongSelect(Room room) + : base(room) + { + } + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new MatchBeatmapDetailArea { CreateNewItem = createNewItem From b719887810f40ad0013fb3ad1f58b115c2dc4581 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 13:34:23 +0900 Subject: [PATCH 597/961] Fix test compile errors --- .../Multiplayer/TestSceneMultiplayerMatchSongSelect.cs | 8 +++++++- .../Visual/Multiplayer/TestScenePlaylistsSongSelect.cs | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index 8bcb9cebbc..0d6b428cce 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -15,6 +15,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Beatmaps; +using osu.Game.Online.Rooms; using osu.Game.Overlays.Mods; using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; @@ -89,7 +90,7 @@ namespace osu.Game.Tests.Visual.Multiplayer SelectedMods.SetDefault(); }); - AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect())); + AddStep("create song select", () => LoadScreen(songSelect = new TestMultiplayerMatchSongSelect(SelectedRoom.Value))); AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); } @@ -168,6 +169,11 @@ namespace osu.Game.Tests.Visual.Multiplayer public new Bindable> FreeMods => base.FreeMods; public new BeatmapCarousel Carousel => base.Carousel; + + public TestMultiplayerMatchSongSelect(Room room, WorkingBeatmap beatmap = null, RulesetInfo ruleset = null) + : base(room, beatmap, ruleset) + { + } } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index e4bf9b36ed..ba30315663 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -93,7 +93,7 @@ namespace osu.Game.Tests.Visual.Multiplayer SelectedMods.Value = Array.Empty(); }); - AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect())); + AddStep("create song select", () => LoadScreen(songSelect = new TestPlaylistsSongSelect(SelectedRoom.Value))); AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); } @@ -183,6 +183,11 @@ namespace osu.Game.Tests.Visual.Multiplayer private class TestPlaylistsSongSelect : PlaylistsSongSelect { public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; + + public TestPlaylistsSongSelect(Room room) + : base(room) + { + } } } } From bf0a1167ec990f64f3f98993f018d2eb758b8395 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 13:35:39 +0900 Subject: [PATCH 598/961] Improve update flow and ensure selected mods is read from local context --- osu.Game/Overlays/Mods/ModButton.cs | 35 ++++++++++------------ osu.Game/Overlays/Mods/ModSelectOverlay.cs | 1 + 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f4233c65cb..247c78152d 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Mods private int selectedIndex = -1; [Resolved] - private Bindable> globalSelectedMods { get; set; } + private Bindable> selectedMods { get; set; } /// /// Change the selected mod index of this button. @@ -245,24 +245,20 @@ namespace osu.Game.Overlays.Mods foregroundIcon.Mod = mod; text.Text = mod.Name; Colour = mod.HasImplementation ? Color4.White : Color4.Gray; - updateCompatibility(mod); + + Scheduler.AddOnce(updateCompatibility); } - private void updateCompatibility(Mod mod) + private void updateCompatibility() { - if (globalSelectedMods != null) - { - if (!globalSelectedMods.Value.Contains(mod)) - { - if (!ModUtils.CheckCompatibleSet(globalSelectedMods.Value.Concat(new[] { mod }))) - { - incompatibleIcon.FadeIn(); - return; - } - } - } + var m = SelectedMod ?? Mods.First(); - incompatibleIcon.FadeOut(); + bool isIncompatible = false; + + if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m)) + isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m)); + + incompatibleIcon.FadeTo(isIncompatible ? 1 : 0, 200, Easing.OutQuint); } private void createIcons() @@ -287,6 +283,7 @@ namespace osu.Game.Overlays.Mods }, }); } + else { iconsContainer.Add(foregroundIcon = new ModIcon(Mod, false) @@ -344,14 +341,14 @@ namespace osu.Game.Overlays.Mods }, new HoverSounds() }; - Mod = mod; } - [BackgroundDependencyLoader] - private void load() + protected override void LoadComplete() { - globalSelectedMods.BindValueChanged(_ => updateCompatibility(SelectedMod ?? Mods.FirstOrDefault()), true); + base.LoadComplete(); + + selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true); } public ITooltip GetCustomTooltip() => new ModButtonTooltip(); diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index 96eba7808f..fdef48d556 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -74,6 +74,7 @@ namespace osu.Game.Overlays.Mods protected readonly ModSettingsContainer ModSettingsContainer; + [Cached] public readonly Bindable> SelectedMods = new Bindable>(Array.Empty()); private Bindable>> availableMods; From 847726547ad9f203c665312ec9ca2d4d027a6be8 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 24 Aug 2021 07:53:49 +0300 Subject: [PATCH 599/961] Move mod value change callback inside wedge info text component --- osu.Game/Screens/Select/BeatmapInfoWedge.cs | 26 +++++++++++---------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index d40e21cd5e..ac191a38f2 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -44,9 +44,6 @@ namespace osu.Game.Screens.Select [Resolved] private IBindable ruleset { get; set; } - [Resolved] - private IBindable> mods { get; set; } - protected Container DisplayedContent { get; private set; } protected WedgeInfoText Info { get; private set; } @@ -71,7 +68,6 @@ namespace osu.Game.Screens.Select private void load() { ruleset.BindValueChanged(_ => updateDisplay()); - mods.BindValueChanged(_ => updateDisplay()); } private const double animation_duration = 800; @@ -138,7 +134,7 @@ namespace osu.Game.Screens.Select Children = new Drawable[] { new BeatmapInfoWedgeBackground(beatmap), - Info = new WedgeInfoText(beatmap, ruleset.Value, mods.Value), + Info = new WedgeInfoText(beatmap, ruleset.Value), } }, loaded => { @@ -169,15 +165,16 @@ namespace osu.Game.Screens.Select private readonly WorkingBeatmap beatmap; private readonly RulesetInfo ruleset; - private readonly IReadOnlyList mods; + + [Resolved] + private IBindable> mods { get; set; } private ModSettingChangeTracker settingChangeTracker; - public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset, IReadOnlyList mods) + public WedgeInfoText(WorkingBeatmap beatmap, RulesetInfo userRuleset) { this.beatmap = beatmap; ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset; - this.mods = mods; } private CancellationTokenSource cancellationSource; @@ -363,10 +360,15 @@ namespace osu.Game.Screens.Select } }; - settingChangeTracker = new ModSettingChangeTracker(mods); - settingChangeTracker.SettingChanged += _ => refreshBPMLabel(); + mods.BindValueChanged(m => + { + settingChangeTracker?.Dispose(); - refreshBPMLabel(); + refreshBPMLabel(); + + settingChangeTracker = new ModSettingChangeTracker(m.NewValue); + settingChangeTracker.SettingChanged += _ => refreshBPMLabel(); + }, true); } private InfoLabel[] getRulesetInfoLabels() @@ -404,7 +406,7 @@ namespace osu.Game.Screens.Select // this doesn't consider mods which apply variable rates, yet. double rate = 1; - foreach (var mod in mods.OfType()) + foreach (var mod in mods.Value.OfType()) rate = mod.ApplyToRate(0, rate); double bpmMax = b.ControlPointInfo.BPMMaximum * rate; From afd01d22d6c29b9bbf1ba6bc0efe344269f1ad64 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 13:58:31 +0900 Subject: [PATCH 600/961] Adjust visuals of incompatible icon and move to own class --- osu.Game/Overlays/Mods/IncompatibleIcon.cs | 64 ++++++++++++++++++++++ osu.Game/Overlays/Mods/ModButton.cs | 17 +++--- 2 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 osu.Game/Overlays/Mods/IncompatibleIcon.cs diff --git a/osu.Game/Overlays/Mods/IncompatibleIcon.cs b/osu.Game/Overlays/Mods/IncompatibleIcon.cs new file mode 100644 index 0000000000..df134fe4a4 --- /dev/null +++ b/osu.Game/Overlays/Mods/IncompatibleIcon.cs @@ -0,0 +1,64 @@ +// 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.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays.Mods +{ + public class IncompatibleIcon : VisibilityContainer, IHasTooltip + { + private Circle circle; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Size = new Vector2(20); + + State.Value = Visibility.Hidden; + Alpha = 0; + + InternalChildren = new Drawable[] + { + circle = new Circle + { + RelativeSizeAxes = Axes.Both, + Colour = colours.Gray4, + }, + new SpriteIcon + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(0.6f), + Icon = FontAwesome.Solid.Slash, + Colour = Color4.White, + Shadow = true, + } + }; + } + + protected override void PopIn() + { + this.FadeIn(200, Easing.OutQuint); + circle.FlashColour(Color4.Red, 500, Easing.OutQuint); + this.ScaleTo(1.8f).Then().ScaleTo(1, 500, Easing.OutQuint); + } + + protected override void PopOut() + { + this.FadeOut(200, Easing.OutQuint); + this.ScaleTo(0.8f, 200, Easing.In); + } + + public LocalisableString TooltipText => "Incompatible with current selected mods"; + } +} diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 247c78152d..76046f2467 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Mods private ModIcon backgroundIcon; private readonly SpriteText text; private readonly Container iconsContainer; - private readonly SpriteIcon incompatibleIcon; + private readonly CompositeDrawable incompatibleIcon; /// /// Fired when the selection changes. @@ -258,7 +258,10 @@ namespace osu.Game.Overlays.Mods if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m)) isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m)); - incompatibleIcon.FadeTo(isIncompatible ? 1 : 0, 200, Easing.OutQuint); + if (isIncompatible) + incompatibleIcon.Show(); + else + incompatibleIcon.Hide(); } private void createIcons() @@ -315,15 +318,11 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.Centre, Anchor = Anchor.Centre, }, - incompatibleIcon = new SpriteIcon + incompatibleIcon = new IncompatibleIcon { - Origin = Anchor.BottomRight, + Origin = Anchor.Centre, Anchor = Anchor.BottomRight, - Icon = FontAwesome.Solid.Ban, - Colour = Color4.Red, - Size = new Vector2(30), - Shadow = true, - Alpha = 0 + Position = new Vector2(-13), } }, RelativeSizeAxes = Axes.Both, From c3b7ce0b059bd90529bf00eb8eadd1db256d1c9c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 14:02:50 +0900 Subject: [PATCH 601/961] Remove stray newline --- osu.Game/Overlays/Mods/ModButton.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 76046f2467..4675eb6bc8 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -286,7 +286,6 @@ namespace osu.Game.Overlays.Mods }, }); } - else { iconsContainer.Add(foregroundIcon = new ModIcon(Mod, false) From 16ddbcd208db9f94765e47e9975c6fa10acb7f3b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 14:25:29 +0900 Subject: [PATCH 602/961] Don't bind to RoomId where it's expected to be constant --- .../Match/Components/MatchChatDisplay.cs | 12 ++++++------ .../OnlinePlay/Multiplayer/MultiplayerPlayer.cs | 7 ++++--- .../OnlinePlay/Playlists/PlaylistsPlayer.cs | 4 ++-- osu.Game/Screens/Play/RoomSubmittingPlayer.cs | 14 +++++++------- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs index 05a3546cec..0396562959 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchChatDisplay.cs @@ -10,36 +10,36 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components { public class MatchChatDisplay : StandAloneChatDisplay { - private readonly IBindable roomId = new Bindable(); private readonly IBindable channelId = new Bindable(); [Resolved(CanBeNull = true)] private ChannelManager channelManager { get; set; } + private readonly Room room; private readonly bool leaveChannelOnDispose; public MatchChatDisplay(Room room, bool leaveChannelOnDispose = true) : base(true) { + this.room = room; this.leaveChannelOnDispose = leaveChannelOnDispose; - - roomId.BindTo(room.RoomID); - channelId.BindTo(room.ChannelId); } protected override void LoadComplete() { base.LoadComplete(); + // Required for the time being since this component is created prior to the room being joined. + channelId.BindTo(room.ChannelId); channelId.BindValueChanged(_ => updateChannel(), true); } private void updateChannel() { - if (roomId.Value == null || channelId.Value == 0) + if (room.RoomID.Value == null || channelId.Value == 0) return; - Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{roomId.Value}" }); + Channel.Value = channelManager?.JoinChannel(new Channel { Id = channelId.Value, Type = ChannelType.Multiplayer, Name = $"#lazermp_{room.RoomID.Value}" }); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs index 4c26feb067..89acda27c3 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs @@ -187,10 +187,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override ResultsScreen CreateResults(ScoreInfo score) { - Debug.Assert(RoomId.Value != null); + Debug.Assert(Room.RoomID.Value != null); + return leaderboard.TeamScores.Count == 2 - ? new MultiplayerTeamResultsScreen(score, RoomId.Value.Value, PlaylistItem, leaderboard.TeamScores) - : new MultiplayerResultsScreen(score, RoomId.Value.Value, PlaylistItem); + ? new MultiplayerTeamResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, leaderboard.TeamScores) + : new MultiplayerResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem); } protected override void Dispose(bool isDisposing) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs index c441728bb6..c76bad7828 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsPlayer.cs @@ -51,8 +51,8 @@ namespace osu.Game.Screens.OnlinePlay.Playlists protected override ResultsScreen CreateResults(ScoreInfo score) { - Debug.Assert(RoomId.Value != null); - return new PlaylistsResultsScreen(score, RoomId.Value.Value, PlaylistItem, true); + Debug.Assert(Room.RoomID.Value != null); + return new PlaylistsResultsScreen(score, Room.RoomID.Value.Value, PlaylistItem, true); } protected override async Task PrepareScoreForResultsAsync(Score score) diff --git a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs index 593b67a7b0..1002e7607f 100644 --- a/osu.Game/Screens/Play/RoomSubmittingPlayer.cs +++ b/osu.Game/Screens/Play/RoomSubmittingPlayer.cs @@ -1,7 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using osu.Framework.Bindables; +using System.Diagnostics; using osu.Game.Online.API; using osu.Game.Online.Rooms; using osu.Game.Scoring; @@ -13,8 +13,6 @@ namespace osu.Game.Screens.Play /// public abstract class RoomSubmittingPlayer : SubmittingPlayer { - protected readonly IBindable RoomId = new Bindable(); - protected readonly PlaylistItem PlaylistItem; protected readonly Room Room; @@ -23,18 +21,20 @@ namespace osu.Game.Screens.Play { Room = room; PlaylistItem = playlistItem; - - RoomId.BindTo(room.RoomID); } protected override APIRequest CreateTokenRequest() { - if (!(RoomId.Value is long roomId)) + if (!(Room.RoomID.Value is long roomId)) return null; return new CreateRoomScoreRequest(roomId, PlaylistItem.ID, Game.VersionHash); } - protected override APIRequest CreateSubmissionRequest(Score score, long token) => new SubmitRoomScoreRequest(token, RoomId.Value ?? 0, PlaylistItem.ID, score.ScoreInfo); + protected override APIRequest CreateSubmissionRequest(Score score, long token) + { + Debug.Assert(Room.RoomID.Value != null); + return new SubmitRoomScoreRequest(token, Room.RoomID.Value.Value, PlaylistItem.ID, score.ScoreInfo); + } } } From 4bbc98737f7a0cba8846f79b909ee2befd338cb6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 14:39:03 +0900 Subject: [PATCH 603/961] Fix english in test steps --- osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4809a737d9..31e5a9b86c 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Online setUpCommentsResponse(comments); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); - AddAssert("no comment showed", () => !commentsContainer.ChildrenOfType().Any()); + AddAssert("no comment shown", () => !commentsContainer.ChildrenOfType().Any()); } [TestCase(false)] @@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Online setUpCommentsResponse(bundle); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); AddUntilStep("wait comment load", () => commentsContainer.ChildrenOfType().Any()); - AddAssert("only one comment showed", () => + AddAssert("only one comment shown", () => commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } From a5f6c287eaeec370c785bf9b4afbf31734d9cceb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 14:43:28 +0900 Subject: [PATCH 604/961] Split out pinned comment content to only be constructed when required --- osu.Game/Overlays/Comments/DrawableComment.cs | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index d80d566f3a..a44f3a7643 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -138,36 +138,13 @@ namespace osu.Game.Overlays.Comments AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(10, 0), - Children = new Drawable[] + Children = new[] { username = new LinkFlowContainer(s => s.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold)) { AutoSizeAxes = Axes.Both }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(2, 0), - Alpha = Comment.Pinned ? 1 : 0, - Children = new Drawable[] - { - new SpriteIcon - { - Icon = FontAwesome.Solid.Thumbtack, - Size = new Vector2(14), - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), - Text = CommentsStrings.Pinned, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - } - }, - }, + Comment.Pinned ? new PinnedCommentNotice() : Empty(), new ParentUsername(Comment), new OsuSpriteText { @@ -346,9 +323,7 @@ namespace osu.Game.Overlays.Comments this.FadeTo(show.NewValue ? 1 : 0); }, true); childrenExpanded.BindValueChanged(expanded => childCommentsVisibilityContainer.FadeTo(expanded.NewValue ? 1 : 0), true); - updateButtonsState(); - base.LoadComplete(); } @@ -417,6 +392,33 @@ namespace osu.Game.Overlays.Comments }; } + private class PinnedCommentNotice : FillFlowContainer + { + public PinnedCommentNotice() + { + AutoSizeAxes = Axes.Both; + Direction = FillDirection.Horizontal; + Spacing = new Vector2(2, 0); + Children = new Drawable[] + { + new SpriteIcon + { + Icon = FontAwesome.Solid.Thumbtack, + Size = new Vector2(14), + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new OsuSpriteText + { + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + Text = CommentsStrings.Pinned, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + } + }; + } + } + private class ParentUsername : FillFlowContainer, IHasTooltip { public LocalisableString TooltipText => getParentMessage(); From 342f2d756d2f8e5f0b340a417b550bd52a18f581 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 15:18:05 +0900 Subject: [PATCH 605/961] Fix test not working intermittently --- osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs index 290ba3317b..4b54cd3510 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHUDOverlay.cs @@ -142,7 +142,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("set hud to never show", () => localConfig.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never)); createNew(); + AddUntilStep("wait for hud load", () => hudOverlay.IsLoaded); + AddUntilStep("wait for components to be hidden", () => !hudOverlay.ChildrenOfType().Single().IsPresent); + + AddStep("reload components", () => hudOverlay.ChildrenOfType().Single().Reload()); AddUntilStep("skinnable components loaded", () => hudOverlay.ChildrenOfType().Single().ComponentsLoaded); } From 9f17c38e36981e8beb5fdd9b3c6d8fb53d991322 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 24 Aug 2021 15:18:27 +0900 Subject: [PATCH 606/961] Fix hud overlay components being blocked from load --- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 53b142f09a..9f94cdd7e7 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -18,6 +18,8 @@ namespace osu.Game.Skinning private readonly BindableList components = new BindableList(); + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; + public bool ComponentsLoaded { get; private set; } public SkinnableTargetContainer(SkinnableTarget target) From 3f0f8206534d226b70de53b9bf1d7fbc8080b831 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 16:54:19 +0900 Subject: [PATCH 607/961] Add comment explaining reasoning for override --- osu.Game/Skinning/SkinnableTargetContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/SkinnableTargetContainer.cs b/osu.Game/Skinning/SkinnableTargetContainer.cs index 9f94cdd7e7..e7125bb034 100644 --- a/osu.Game/Skinning/SkinnableTargetContainer.cs +++ b/osu.Game/Skinning/SkinnableTargetContainer.cs @@ -18,7 +18,7 @@ namespace osu.Game.Skinning private readonly BindableList components = new BindableList(); - public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; + public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks; // ensure that components are loaded even if the target container is hidden (ie. due to user toggle). public bool ComponentsLoaded { get; private set; } From 6252b8aa42a29e06dcf19a128a77b9dd2d362c9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 19:05:45 +0900 Subject: [PATCH 608/961] Fix hold notes handling all input ever --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs | 3 +-- .../Objects/Drawables/DrawableHoldNoteHead.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs index d1310d42eb..2923a2af2f 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs @@ -275,9 +275,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables return false; beginHoldAt(Time.Current - Head.HitObject.StartTime); - Head.UpdateResult(); - return true; + return Head.UpdateResult(); } private void beginHoldAt(double timeOffset) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs index be600f0d47..8458345998 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNoteHead.cs @@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables Origin = Anchor.TopCentre; } - public void UpdateResult() => base.UpdateResult(true); + public bool UpdateResult() => base.UpdateResult(true); protected override void UpdateInitialTransforms() { From a6c2cbd2e593224b0aef26e2a117e5707bbd6bf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Aug 2021 20:53:27 +0200 Subject: [PATCH 609/961] Add countdown settings to beatmap info model --- .../Formats/LegacyBeatmapDecoderTest.cs | 3 +- .../Beatmaps/Formats/OsuJsonDecoderTest.cs | 3 +- osu.Game/Beatmaps/BeatmapInfo.cs | 4 +- osu.Game/Beatmaps/CountdownType.cs | 16 + .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 12 +- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 7 +- ...824185035_AddCountdownSettings.Designer.cs | 513 ++++++++++++++++++ .../20210824185035_AddCountdownSettings.cs | 23 + .../Migrations/OsuDbContextModelSnapshot.cs | 4 +- 9 files changed, 573 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Beatmaps/CountdownType.cs create mode 100644 osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs create mode 100644 osu.Game/Migrations/20210824185035_AddCountdownSettings.cs diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 4fe1cf3790..dd4c24698c 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -58,12 +58,13 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", metadata.AudioFile); Assert.AreEqual(0, beatmapInfo.AudioLeadIn); Assert.AreEqual(164471, metadata.PreviewTime); - Assert.IsFalse(beatmapInfo.Countdown); Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); Assert.IsTrue(beatmapInfo.RulesetID == 0); Assert.IsFalse(beatmapInfo.LetterboxInBreaks); Assert.IsFalse(beatmapInfo.SpecialStyle); Assert.IsFalse(beatmapInfo.WidescreenStoryboard); + Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown); + Assert.AreEqual(0, beatmapInfo.CountdownOffset); } } diff --git a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs index e97c83e2c2..1fc3abef9a 100644 --- a/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/OsuJsonDecoderTest.cs @@ -50,12 +50,13 @@ namespace osu.Game.Tests.Beatmaps.Formats var beatmap = decodeAsJson(normal); var beatmapInfo = beatmap.BeatmapInfo; Assert.AreEqual(0, beatmapInfo.AudioLeadIn); - Assert.AreEqual(false, beatmapInfo.Countdown); Assert.AreEqual(0.7f, beatmapInfo.StackLeniency); Assert.AreEqual(false, beatmapInfo.SpecialStyle); Assert.IsTrue(beatmapInfo.RulesetID == 0); Assert.AreEqual(false, beatmapInfo.LetterboxInBreaks); Assert.AreEqual(false, beatmapInfo.WidescreenStoryboard); + Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown); + Assert.AreEqual(0, beatmapInfo.CountdownOffset); } [Test] diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 36cb97e8d7..fe734cd1b5 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -83,7 +83,6 @@ namespace osu.Game.Beatmaps // General public double AudioLeadIn { get; set; } - public bool Countdown { get; set; } = true; public float StackLeniency { get; set; } = 0.7f; public bool SpecialStyle { get; set; } @@ -95,6 +94,9 @@ namespace osu.Game.Beatmaps public bool WidescreenStoryboard { get; set; } public bool EpilepsyWarning { get; set; } + public CountdownType Countdown { get; set; } = CountdownType.Normal; + public int CountdownOffset { get; set; } + // Editor // This bookmarks stuff is necessary because DB doesn't know how to store int[] [JsonIgnore] diff --git a/osu.Game/Beatmaps/CountdownType.cs b/osu.Game/Beatmaps/CountdownType.cs new file mode 100644 index 0000000000..1831b4576b --- /dev/null +++ b/osu.Game/Beatmaps/CountdownType.cs @@ -0,0 +1,16 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Beatmaps +{ + /// + /// The type of countdown shown before the start of gameplay on a given beatmap. + /// + public enum CountdownType + { + None = 0, + Normal = 1, + HalfSpeed = 2, + DoubleSpeed = 3 + } +} diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 40bc75e847..0ddc9e4c48 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -121,10 +121,6 @@ namespace osu.Game.Beatmaps.Formats metadata.PreviewTime = getOffsetTime(Parsing.ParseInt(pair.Value)); break; - case @"Countdown": - beatmap.BeatmapInfo.Countdown = Parsing.ParseInt(pair.Value) == 1; - break; - case @"SampleSet": defaultSampleBank = (LegacySampleBank)Enum.Parse(typeof(LegacySampleBank), pair.Value); break; @@ -176,6 +172,14 @@ namespace osu.Game.Beatmaps.Formats case @"EpilepsyWarning": beatmap.BeatmapInfo.EpilepsyWarning = Parsing.ParseInt(pair.Value) == 1; break; + + case @"Countdown": + beatmap.BeatmapInfo.Countdown = (CountdownType)Enum.Parse(typeof(CountdownType), pair.Value); + break; + + case @"CountdownOffset": + beatmap.BeatmapInfo.CountdownOffset = Parsing.ParseInt(pair.Value); + break; } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 524b556ddc..fade7183a3 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -79,8 +79,7 @@ namespace osu.Game.Beatmaps.Formats if (beatmap.Metadata.AudioFile != null) writer.WriteLine(FormattableString.Invariant($"AudioFilename: {Path.GetFileName(beatmap.Metadata.AudioFile)}")); writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}")); writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}")); - // Todo: Not all countdown types are supported by lazer yet - writer.WriteLine(FormattableString.Invariant($"Countdown: {(beatmap.BeatmapInfo.Countdown ? '1' : '0')}")); + writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}")); writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank(beatmap.ControlPointInfo.SamplePointAt(double.MinValue).SampleBank)}")); writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}")); writer.WriteLine(FormattableString.Invariant($"Mode: {beatmap.BeatmapInfo.RulesetID}")); @@ -95,8 +94,8 @@ namespace osu.Game.Beatmaps.Formats // writer.WriteLine(@"SkinPreference:" + b.SkinPreference); if (beatmap.BeatmapInfo.EpilepsyWarning) writer.WriteLine(@"EpilepsyWarning: 1"); - // if (b.CountdownOffset > 0) - // writer.WriteLine(@"CountdownOffset: " + b.CountdownOffset.ToString()); + if (beatmap.BeatmapInfo.CountdownOffset > 0) + writer.WriteLine(FormattableString.Invariant($@"CountdownOffset: {beatmap.BeatmapInfo.CountdownOffset}")); if (beatmap.BeatmapInfo.RulesetID == 3) writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}")); writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}")); diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs new file mode 100644 index 0000000000..afeb42130d --- /dev/null +++ b/osu.Game/Migrations/20210824185035_AddCountdownSettings.Designer.cs @@ -0,0 +1,513 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using osu.Game.Database; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20210824185035_AddCountdownSettings")] + partial class AddCountdownSettings + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BPM"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("CountdownOffset"); + + b.Property("DistanceSpacing"); + + b.Property("EpilepsyWarning"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("Length"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("Status"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorID") + .HasColumnName("AuthorID"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.Property("Status"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Key") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("SkinInfoID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("SkinInfoID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("ScoreInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("ScoreInfoID"); + + b.ToTable("ScoreFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Accuracy") + .HasColumnType("DECIMAL(1,4)"); + + b.Property("BeatmapInfoID"); + + b.Property("Combo"); + + b.Property("Date"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MaxCombo"); + + b.Property("ModsJson") + .HasColumnName("Mods"); + + b.Property("OnlineScoreID"); + + b.Property("PP"); + + b.Property("Rank"); + + b.Property("RulesetID"); + + b.Property("StatisticsJson") + .HasColumnName("Statistics"); + + b.Property("TotalScore"); + + b.Property("UserID") + .HasColumnName("UserID"); + + b.Property("UserString") + .HasColumnName("User"); + + b.HasKey("ID"); + + b.HasIndex("BeatmapInfoID"); + + b.HasIndex("OnlineScoreID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("ScoreInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Settings") + .HasForeignKey("SkinInfoID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Scoring.ScoreInfo") + .WithMany("Files") + .HasForeignKey("ScoreInfoID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") + .WithMany("Scores") + .HasForeignKey("BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs b/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs new file mode 100644 index 0000000000..564f5f4520 --- /dev/null +++ b/osu.Game/Migrations/20210824185035_AddCountdownSettings.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace osu.Game.Migrations +{ + public partial class AddCountdownSettings : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CountdownOffset", + table: "BeatmapInfo", + nullable: false, + defaultValue: 0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CountdownOffset", + table: "BeatmapInfo"); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index f518cfb42b..470907ada6 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -53,7 +53,9 @@ namespace osu.Game.Migrations b.Property("BeatmapSetInfoID"); - b.Property("Countdown"); + b.Property("Countdown"); + + b.Property("CountdownOffset"); b.Property("DistanceSpacing"); From acc27fc79c390c24a450a27f7a316c165f88fccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 24 Aug 2021 22:04:56 +0200 Subject: [PATCH 610/961] Add test case for countdown in encode-decode stability test --- osu.Game.Tests/Resources/countdown-settings.osu | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 osu.Game.Tests/Resources/countdown-settings.osu diff --git a/osu.Game.Tests/Resources/countdown-settings.osu b/osu.Game.Tests/Resources/countdown-settings.osu new file mode 100644 index 0000000000..333e48150d --- /dev/null +++ b/osu.Game.Tests/Resources/countdown-settings.osu @@ -0,0 +1,5 @@ +osu file format v14 + +[General] +Countdown: 2 +CountdownOffset: 3 From 414457ba57138b20f5582235fbbe09d9108ef861 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 13:24:52 +0900 Subject: [PATCH 611/961] Add basic xmldoc explaining `CountdownOffset` --- osu.Game/Beatmaps/BeatmapInfo.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index fe734cd1b5..353636c8af 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -95,6 +95,10 @@ namespace osu.Game.Beatmaps public bool EpilepsyWarning { get; set; } public CountdownType Countdown { get; set; } = CountdownType.Normal; + + /// + /// The number of beats to move the countdown backwards (compared to its default location). + /// public int CountdownOffset { get; set; } // Editor From 84637b59ef836b88f61842e4543920f3729d02be Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 07:40:41 +0300 Subject: [PATCH 612/961] Define `DifficultyBindableWithCurrent` and use in `SliderControl` --- .../Mods/DifficultyAdjustSettingsControl.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs index 3978378c3a..67b24d24d0 100644 --- a/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs +++ b/osu.Game/Rulesets/Mods/DifficultyAdjustSettingsControl.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -91,7 +92,7 @@ namespace osu.Game.Rulesets.Mods { // This is required as SettingsItem relies heavily on this bindable for internal use. // The actual update flow is done via the bindable provided in the constructor. - private readonly BindableWithCurrent current = new BindableWithCurrent(); + private readonly DifficultyBindableWithCurrent current = new DifficultyBindableWithCurrent(); public Bindable Current { @@ -114,5 +115,30 @@ namespace osu.Game.Rulesets.Mods RelativeSizeAxes = Axes.X; } } + + private class DifficultyBindableWithCurrent : DifficultyBindable, IHasCurrentValue + { + private Bindable currentBound; + + public Bindable Current + { + get => this; + set + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + if (currentBound != null) UnbindFrom(currentBound); + BindTo(currentBound = value); + } + } + + public DifficultyBindableWithCurrent(float? defaultValue = default) + : base(defaultValue) + { + } + + protected override Bindable CreateInstance() => new DifficultyBindableWithCurrent(); + } } } From e1ab3434ed9feca60ebb6440947a79f318bad808 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 14:25:57 +0900 Subject: [PATCH 613/961] Add ability to handle user join/leave/kick events in `MultiplayerComposite`s --- .../Online/Multiplayer/MultiplayerClient.cs | 36 ++++++++++++------- .../Multiplayer/MultiplayerRoomComposite.cs | 34 ++++++++++++++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs index 2a0635c98c..75bbaec0ef 100644 --- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs +++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs @@ -33,6 +33,12 @@ namespace osu.Game.Online.Multiplayer /// public event Action? RoomUpdated; + public event Action? UserJoined; + + public event Action? UserLeft; + + public event Action? UserKicked; + /// /// Invoked when the multiplayer server requests the current beatmap to be loaded into play. /// @@ -366,11 +372,26 @@ namespace osu.Game.Online.Multiplayer Room.Users.Add(user); + UserJoined?.Invoke(user); RoomUpdated?.Invoke(); }, false); } - Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) + Task IMultiplayerClient.UserLeft(MultiplayerRoomUser user) => + handleUserLeft(user, UserLeft); + + Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user) + { + if (LocalUser == null) + return Task.CompletedTask; + + if (user.Equals(LocalUser)) + LeaveRoom(); + + return handleUserLeft(user, UserKicked); + } + + private Task handleUserLeft(MultiplayerRoomUser user, Action? callback) { if (Room == null) return Task.CompletedTask; @@ -383,24 +404,13 @@ namespace osu.Game.Online.Multiplayer Room.Users.Remove(user); PlayingUserIds.Remove(user.UserID); + callback?.Invoke(user); RoomUpdated?.Invoke(); }, false); return Task.CompletedTask; } - Task IMultiplayerClient.UserKicked(MultiplayerRoomUser user) - { - if (LocalUser == null) - return Task.CompletedTask; - - if (user.Equals(LocalUser)) - LeaveRoom(); - - // TODO: also inform users of the kick operation. - return ((IMultiplayerClient)this).UserLeft(user); - } - Task IMultiplayerClient.HostChanged(int userId) { if (Room == null) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs index d334c618f5..0f256160eb 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerRoomComposite.cs @@ -20,9 +20,38 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer base.LoadComplete(); Client.RoomUpdated += OnRoomUpdated; + + Client.UserLeft += UserLeft; + Client.UserKicked += UserKicked; + Client.UserJoined += UserJoined; + OnRoomUpdated(); } + /// + /// Invoked when a user has joined the room. + /// + /// The user. + protected virtual void UserJoined(MultiplayerRoomUser user) + { + } + + /// + /// Invoked when a user has been kicked from the room (including the local user). + /// + /// The user. + protected virtual void UserKicked(MultiplayerRoomUser user) + { + } + + /// + /// Invoked when a user has left the room. + /// + /// The user. + protected virtual void UserLeft(MultiplayerRoomUser user) + { + } + /// /// Invoked when any change occurs to the multiplayer room. /// @@ -33,7 +62,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer protected override void Dispose(bool isDisposing) { if (Client != null) + { + Client.UserLeft -= UserLeft; + Client.UserKicked -= UserKicked; + Client.UserJoined -= UserJoined; Client.RoomUpdated -= OnRoomUpdated; + } base.Dispose(isDisposing); } From 6aa894e55e0f25d184125efa649c610ef6816648 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 18:23:02 +0900 Subject: [PATCH 614/961] Split out separate component --- .../Drawables/DrawableManiaHitObject.cs | 6 -- osu.Game.Rulesets.Mania/UI/Column.cs | 38 ++------- .../Objects/Drawables/DrawableHitObject.cs | 5 ++ .../UI/GameplaySampleTriggerSource.cs | 84 +++++++++++++++++++ 4 files changed, 94 insertions(+), 39 deletions(-) create mode 100644 osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs index 5aff4e200b..9ac223a0d7 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableManiaHitObject.cs @@ -6,7 +6,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Game.Audio; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI.Scrolling; using osu.Game.Rulesets.Mania.UI; @@ -29,11 +28,6 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables [Resolved(canBeNull: true)] private ManiaPlayfield playfield { get; set; } - /// - /// Gets the samples that are played by this object during gameplay. - /// - public ISampleInfo[] GetGameplaySamples() => Samples.Samples; - protected override float SamplePlaybackPosition { get diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs index 9b5893b268..f5e30efd91 100644 --- a/osu.Game.Rulesets.Mania/UI/Column.cs +++ b/osu.Game.Rulesets.Mania/UI/Column.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 osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,6 +18,7 @@ using osuTK; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.UI; namespace osu.Game.Rulesets.Mania.UI { @@ -28,12 +28,6 @@ namespace osu.Game.Rulesets.Mania.UI public const float COLUMN_WIDTH = 80; public const float SPECIAL_COLUMN_WIDTH = 70; - /// - /// For hitsounds played by this (i.e. not as a result of hitting a hitobject), - /// a certain number of samples are allowed to be played concurrently so that it feels better when spam-pressing the key. - /// - private const int max_concurrent_hitsounds = OsuGameBase.SAMPLE_CONCURRENCY; - /// /// The index of this column as part of the whole playfield. /// @@ -45,10 +39,10 @@ namespace osu.Game.Rulesets.Mania.UI internal readonly Container TopLevelContainer; private readonly DrawablePool hitExplosionPool; private readonly OrderedHitPolicy hitPolicy; - private readonly Container hitSounds; - public Container UnderlayElements => HitObjectArea.UnderlayElements; + private readonly GameplaySampleTriggerSource sampleTriggerSource; + public Column(int index) { Index = index; @@ -64,6 +58,7 @@ namespace osu.Game.Rulesets.Mania.UI InternalChildren = new[] { hitExplosionPool = new DrawablePool(5), + sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer), // For input purposes, the background is added at the highest depth, but is then proxied back below all other elements background.CreateProxy(), HitObjectArea = new ColumnHitObjectArea(Index, HitObjectContainer) { RelativeSizeAxes = Axes.Both }, @@ -72,12 +67,6 @@ namespace osu.Game.Rulesets.Mania.UI RelativeSizeAxes = Axes.Both }, background, - hitSounds = new Container - { - Name = "Column samples pool", - RelativeSizeAxes = Axes.Both, - Children = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()).ToArray() - }, TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both } }; @@ -133,29 +122,12 @@ namespace osu.Game.Rulesets.Mania.UI HitObjectArea.Explosions.Add(hitExplosionPool.Get(e => e.Apply(result))); } - private int nextHitSoundIndex; - public bool OnPressed(ManiaAction action) { if (action != Action.Value) return false; - var nextObject = - HitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? - // fallback to non-alive objects to find next off-screen object - HitObjectContainer.Objects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current) ?? - HitObjectContainer.Objects.LastOrDefault(); - - if (nextObject is DrawableManiaHitObject maniaObject) - { - var hitSound = hitSounds[nextHitSoundIndex]; - - hitSound.Samples = maniaObject.GetGameplaySamples(); - hitSound.Play(); - - nextHitSoundIndex = (nextHitSoundIndex + 1) % max_concurrent_hitsounds; - } - + sampleTriggerSource.Play(); return true; } diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 29d8a475ef..b3e1b24d8d 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -54,6 +54,11 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public readonly Bindable AccentColour = new Bindable(Color4.Gray); + /// + /// Gets the samples that are played by this object during gameplay. + /// + public ISampleInfo[] GetGameplaySamples() => Samples.Samples; + protected PausableSkinnableSound Samples { get; private set; } public virtual IEnumerable GetSamples() => HitObject.Samples; diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs new file mode 100644 index 0000000000..fedbcd541c --- /dev/null +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -0,0 +1,84 @@ +// 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.Audio; +using osu.Game.Rulesets.Objects; +using osu.Game.Skinning; + +namespace osu.Game.Rulesets.UI +{ + /// + /// A component which can trigger the most appropriate hit sound for a given point in time, based on the state of a + /// + public class GameplaySampleTriggerSource : CompositeDrawable + { + private readonly HitObjectContainer hitObjectContainer; + + private int nextHitSoundIndex; + + /// + /// The number of concurrent samples allowed to be played concurrently so that it feels better when spam-pressing a key. + /// + private const int max_concurrent_hitsounds = OsuGameBase.SAMPLE_CONCURRENCY; + + private readonly Container hitSounds; + + [Resolved] + private DrawableRuleset drawableRuleset { get; set; } + + public GameplaySampleTriggerSource(HitObjectContainer hitObjectContainer) + { + this.hitObjectContainer = hitObjectContainer; + InternalChildren = new Drawable[] + { + hitSounds = new Container + { + Name = "concurrent sample pool", + RelativeSizeAxes = Axes.Both, + Children = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()).ToArray() + }, + }; + } + + private ISampleInfo[] playableSampleInfo; + + /// + /// Play the most appropriate hit sound for the current point in time. + /// + public void Play() + { + var nextObject = + hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject ?? + // fallback to non-alive objects to find next off-screen object + // TODO: make lookup more efficient? + drawableRuleset.Objects.FirstOrDefault(h => h.StartTime > Time.Current) ?? + drawableRuleset.Objects.LastOrDefault(); + + if (nextObject != null) + { + var hitSound = getNextSample(); + playableSampleInfo = GetPlayableSampleInfo(nextObject); + hitSound.Samples = playableSampleInfo; + hitSound.Play(); + } + } + + protected virtual ISampleInfo[] GetPlayableSampleInfo(HitObject nextObject) => + // TODO: avoid cast somehow? + nextObject.Samples.Cast().ToArray(); + + private SkinnableSound getNextSample() + { + var hitSound = hitSounds[nextHitSoundIndex]; + + // round robin over available samples to allow for concurrent playback. + nextHitSoundIndex = (nextHitSoundIndex + 1) % max_concurrent_hitsounds; + + return hitSound; + } + } +} From 4a294d4de47c9cef709457ee8cf8357be11aa894 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 24 Aug 2021 19:05:59 +0900 Subject: [PATCH 615/961] Optimise fallback logic to reduce lookups to bare minimum --- .../UI/GameplaySampleTriggerSource.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index fedbcd541c..51f3052509 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -44,32 +44,44 @@ namespace osu.Game.Rulesets.UI }; } - private ISampleInfo[] playableSampleInfo; + private HitObject fallbackObject; /// /// Play the most appropriate hit sound for the current point in time. /// public void Play() { - var nextObject = - hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject ?? - // fallback to non-alive objects to find next off-screen object - // TODO: make lookup more efficient? - drawableRuleset.Objects.FirstOrDefault(h => h.StartTime > Time.Current) ?? - drawableRuleset.Objects.LastOrDefault(); + var nextObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; + + if (nextObject == null) + { + if (fallbackObject == null || fallbackObject.StartTime < Time.Current) + { + // in the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. + // note that we don't want to cache the object if it is an alive object, as once it is hit we don't want to continue playing its sound. + // check whether we can use the previous computed sample. + + // fallback to non-alive objects to find next off-screen object + // TODO: make lookup more efficient? + fallbackObject = hitObjectContainer.Entries + .Where(e => e.Result?.HasResult != true && e.HitObject.StartTime > Time.Current)? + .OrderBy(e => e.HitObject.StartTime) + .FirstOrDefault()?.HitObject ?? hitObjectContainer.Entries.FirstOrDefault()?.HitObject; + } + + nextObject = fallbackObject; + } if (nextObject != null) { var hitSound = getNextSample(); - playableSampleInfo = GetPlayableSampleInfo(nextObject); - hitSound.Samples = playableSampleInfo; + hitSound.Samples = GetPlayableSampleInfo(nextObject).Select(s => nextObject.SampleControlPoint.ApplyTo(s)).Cast().ToArray(); hitSound.Play(); } } - protected virtual ISampleInfo[] GetPlayableSampleInfo(HitObject nextObject) => - // TODO: avoid cast somehow? - nextObject.Samples.Cast().ToArray(); + protected virtual HitSampleInfo[] GetPlayableSampleInfo(HitObject nextObject) => + nextObject.Samples.ToArray(); private SkinnableSound getNextSample() { From 681215e5b58a799edc1c9e4098e9a781a5011105 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 14:57:41 +0900 Subject: [PATCH 616/961] Rewrite object lookup to use previous entry regardless This changes the fallback logic to always prefer the previous resolved lifetime entry rather than fallback to the first entry ever. I think this is more correct in all cases. Also rewrites the inline comments to hopefully be easier to parse. --- .../UI/GameplaySampleTriggerSource.cs | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index 51f3052509..1713104f01 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -16,15 +16,15 @@ namespace osu.Game.Rulesets.UI /// public class GameplaySampleTriggerSource : CompositeDrawable { - private readonly HitObjectContainer hitObjectContainer; - - private int nextHitSoundIndex; - /// /// The number of concurrent samples allowed to be played concurrently so that it feels better when spam-pressing a key. /// private const int max_concurrent_hitsounds = OsuGameBase.SAMPLE_CONCURRENCY; + private readonly HitObjectContainer hitObjectContainer; + + private int nextHitSoundIndex; + private readonly Container hitSounds; [Resolved] @@ -44,32 +44,38 @@ namespace osu.Game.Rulesets.UI }; } - private HitObject fallbackObject; + private HitObjectLifetimeEntry fallbackObject; /// /// Play the most appropriate hit sound for the current point in time. /// public void Play() { + // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. var nextObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; + // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. if (nextObject == null) { - if (fallbackObject == null || fallbackObject.StartTime < Time.Current) + // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). + if (fallbackObject == null || fallbackObject.HitObject.StartTime < Time.Current || fallbackObject.Result.IsHit) { - // in the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. - // note that we don't want to cache the object if it is an alive object, as once it is hit we don't want to continue playing its sound. - // check whether we can use the previous computed sample. + // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). + // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. + var lookup = hitObjectContainer.Entries + .Where(e => e.Result?.HasResult != true && e.HitObject.StartTime > Time.Current) + .OrderBy(e => e.HitObject.StartTime) + .FirstOrDefault(); - // fallback to non-alive objects to find next off-screen object - // TODO: make lookup more efficient? - fallbackObject = hitObjectContainer.Entries - .Where(e => e.Result?.HasResult != true && e.HitObject.StartTime > Time.Current)? - .OrderBy(e => e.HitObject.StartTime) - .FirstOrDefault()?.HitObject ?? hitObjectContainer.Entries.FirstOrDefault()?.HitObject; + // If the lookup failed, use the previously resolved lookup (we still want to play a sound, and it is still likely the most valid result). + if (lookup != null) + fallbackObject = lookup; + + // If we still can't find anything, just play whatever we can to get a sound out. + fallbackObject ??= hitObjectContainer.Entries.FirstOrDefault(); } - nextObject = fallbackObject; + nextObject = fallbackObject?.HitObject; } if (nextObject != null) From a1936b141bb3acf91e79ca6725d14b5300e114fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 15:24:01 +0900 Subject: [PATCH 617/961] Refactor base class to allow correct usage in taiko drum --- .../UI/GameplaySampleTriggerSource.cs | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index 1713104f01..015c85beb9 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -49,7 +49,29 @@ namespace osu.Game.Rulesets.UI /// /// Play the most appropriate hit sound for the current point in time. /// - public void Play() + public virtual void Play() + { + var nextObject = GetMostValidObject(); + + if (nextObject == null) + return; + + var samples = nextObject.Samples + .Select(s => nextObject.SampleControlPoint.ApplyTo(s)) + .Cast() + .ToArray(); + + PlaySamples(samples); + } + + protected void PlaySamples(ISampleInfo[] samples) + { + var hitSound = getNextSample(); + hitSound.Samples = samples; + hitSound.Play(); + } + + protected HitObject GetMostValidObject() { // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. var nextObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; @@ -58,7 +80,7 @@ namespace osu.Game.Rulesets.UI if (nextObject == null) { // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). - if (fallbackObject == null || fallbackObject.HitObject.StartTime < Time.Current || fallbackObject.Result.IsHit) + if (fallbackObject == null || fallbackObject.HitObject.StartTime < Time.Current || fallbackObject.Result?.IsHit == true) { // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. @@ -78,17 +100,9 @@ namespace osu.Game.Rulesets.UI nextObject = fallbackObject?.HitObject; } - if (nextObject != null) - { - var hitSound = getNextSample(); - hitSound.Samples = GetPlayableSampleInfo(nextObject).Select(s => nextObject.SampleControlPoint.ApplyTo(s)).Cast().ToArray(); - hitSound.Play(); - } + return nextObject; } - protected virtual HitSampleInfo[] GetPlayableSampleInfo(HitObject nextObject) => - nextObject.Samples.ToArray(); - private SkinnableSound getNextSample() { var hitSound = hitSounds[nextHitSoundIndex]; From 8e0a04c4e5c2f4d8a40867856f90832f34b6e500 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 15:24:13 +0900 Subject: [PATCH 618/961] Update taiko `InputDrum` to use new trigger logic --- .../Skinning/TestSceneDrawableBarLine.cs | 4 +- .../Skinning/TestSceneInputDrum.cs | 10 +- .../Skinning/TestSceneTaikoPlayfield.cs | 2 +- .../Audio/DrumSampleContainer.cs | 104 ------------------ .../Skinning/Legacy/LegacyInputDrum.cs | 10 +- .../UI/DrawableTaikoRuleset.cs | 2 +- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 43 ++++++-- osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs | 10 +- 8 files changed, 49 insertions(+), 136 deletions(-) delete mode 100644 osu.Game.Rulesets.Taiko/Audio/DrumSampleContainer.cs diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs index f9b8e9a985..269a855219 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableBarLine.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Origin = Anchor.Centre, Children = new Drawable[] { - new TaikoPlayfield(new ControlPointInfo()), + new TaikoPlayfield(), hoc = new ScrollingHitObjectContainer() } }; @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Origin = Anchor.Centre, Children = new Drawable[] { - new TaikoPlayfield(new ControlPointInfo()), + new TaikoPlayfield(), hoc = new ScrollingHitObjectContainer() } }; diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs index 055a292fe8..24db046748 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneInputDrum.cs @@ -5,7 +5,6 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Taiko.UI; using osuTK; @@ -17,6 +16,13 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning [BackgroundDependencyLoader] private void load() { + var playfield = new TaikoPlayfield(); + + var beatmap = CreateWorkingBeatmap(new TaikoRuleset().RulesetInfo).GetPlayableBeatmap(new TaikoRuleset().RulesetInfo); + + foreach (var h in beatmap.HitObjects) + playfield.Add(h); + SetContents(_ => new TaikoInputManager(new TaikoRuleset().RulesetInfo) { RelativeSizeAxes = Axes.Both, @@ -25,7 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Anchor = Anchor.Centre, Origin = Anchor.Centre, Size = new Vector2(200), - Child = new InputDrum(new ControlPointInfo()) + Child = new InputDrum(playfield.HitObjectContainer) } }); } diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs index f96297a06d..6f2fcd08f1 100644 --- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneTaikoPlayfield.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning Beatmap.Value.Track.Start(); }); - AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield(new ControlPointInfo()) + AddStep("Load playfield", () => SetContents(_ => new TaikoPlayfield { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, diff --git a/osu.Game.Rulesets.Taiko/Audio/DrumSampleContainer.cs b/osu.Game.Rulesets.Taiko/Audio/DrumSampleContainer.cs deleted file mode 100644 index e4dc261363..0000000000 --- a/osu.Game.Rulesets.Taiko/Audio/DrumSampleContainer.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Audio; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Skinning; - -namespace osu.Game.Rulesets.Taiko.Audio -{ - /// - /// Stores samples for the input drum. - /// The lifetime of the samples is adjusted so that they are only alive during the appropriate sample control point. - /// - public class DrumSampleContainer : LifetimeManagementContainer - { - private readonly ControlPointInfo controlPoints; - private readonly Dictionary mappings = new Dictionary(); - - private readonly IBindableList samplePoints = new BindableList(); - - public DrumSampleContainer(ControlPointInfo controlPoints) - { - this.controlPoints = controlPoints; - } - - [BackgroundDependencyLoader] - private void load() - { - samplePoints.BindTo(controlPoints.SamplePoints); - samplePoints.BindCollectionChanged((_, __) => recreateMappings(), true); - } - - private void recreateMappings() - { - mappings.Clear(); - ClearInternal(); - - SampleControlPoint[] points = samplePoints.Count == 0 - ? new[] { controlPoints.SamplePointAt(double.MinValue) } - : samplePoints.ToArray(); - - for (int i = 0; i < points.Length; i++) - { - var samplePoint = points[i]; - - var lifetimeStart = i > 0 ? samplePoint.Time : double.MinValue; - var lifetimeEnd = i + 1 < points.Length ? points[i + 1].Time : double.MaxValue; - - AddInternal(mappings[samplePoint.Time] = new DrumSample(samplePoint) - { - LifetimeStart = lifetimeStart, - LifetimeEnd = lifetimeEnd - }); - } - } - - public DrumSample SampleAt(double time) => mappings[controlPoints.SamplePointAt(time).Time]; - - public class DrumSample : CompositeDrawable - { - public override bool RemoveWhenNotAlive => false; - - public PausableSkinnableSound Centre { get; private set; } - public PausableSkinnableSound Rim { get; private set; } - - private readonly SampleControlPoint samplePoint; - - private Bindable sampleBank; - private BindableNumber sampleVolume; - - public DrumSample(SampleControlPoint samplePoint) - { - this.samplePoint = samplePoint; - } - - [BackgroundDependencyLoader] - private void load() - { - sampleBank = samplePoint.SampleBankBindable.GetBoundCopy(); - sampleBank.BindValueChanged(_ => recreate()); - - sampleVolume = samplePoint.SampleVolumeBindable.GetBoundCopy(); - sampleVolume.BindValueChanged(_ => recreate()); - - recreate(); - } - - private void recreate() - { - InternalChildren = new Drawable[] - { - Centre = new PausableSkinnableSound(samplePoint.GetSampleInfo()), - Rim = new PausableSkinnableSound(samplePoint.GetSampleInfo(HitSampleInfo.HIT_CLAP)) - }; - } - } - } -} diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 795885d4b9..5a76694913 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -7,7 +7,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; -using osu.Game.Rulesets.Taiko.Audio; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.Taiko.UI; using osu.Game.Skinning; using osuTK; @@ -111,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public readonly Sprite Centre; [Resolved] - private DrumSampleContainer sampleContainer { get; set; } + private InputDrum.DrumSampleTriggerSource sampleTriggerSource { get; set; } public LegacyHalfDrum(bool flipped) { @@ -143,17 +144,16 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public bool OnPressed(TaikoAction action) { Drawable target = null; - var drumSample = sampleContainer.SampleAt(Time.Current); if (action == CentreAction) { target = Centre; - drumSample.Centre?.Play(); + sampleTriggerSource.Play(HitType.Centre); } else if (action == RimAction) { target = Rim; - drumSample.Rim?.Play(); + sampleTriggerSource.Play(HitType.Rim); } if (target != null) diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index 650ce1f5a3..6ddbf3c16b 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Taiko.UI protected override PassThroughInputManager CreateInputManager() => new TaikoInputManager(Ruleset.RulesetInfo); - protected override Playfield CreatePlayfield() => new TaikoPlayfield(Beatmap.ControlPointInfo); + protected override Playfield CreatePlayfield() => new TaikoPlayfield(); public override DrawableHitObject CreateDrawableRepresentation(TaikoHitObject h) => null; diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 1ca1be1bdf..24e2dddb49 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -2,18 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osuTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; -using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Audio; using osu.Game.Graphics; -using osu.Game.Rulesets.Taiko.Audio; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using osu.Game.Skinning; +using osuTK; namespace osu.Game.Rulesets.Taiko.UI { @@ -25,11 +26,11 @@ namespace osu.Game.Rulesets.Taiko.UI private const float middle_split = 0.025f; [Cached] - private DrumSampleContainer sampleContainer; + private DrumSampleTriggerSource sampleTriggerSource; - public InputDrum(ControlPointInfo controlPoints) + public InputDrum(HitObjectContainer hitObjectContainer) { - sampleContainer = new DrumSampleContainer(controlPoints); + sampleTriggerSource = new DrumSampleTriggerSource(hitObjectContainer); RelativeSizeAxes = Axes.Both; } @@ -70,7 +71,7 @@ namespace osu.Game.Rulesets.Taiko.UI } } }), - sampleContainer + sampleTriggerSource }; } @@ -95,7 +96,7 @@ namespace osu.Game.Rulesets.Taiko.UI private readonly Sprite centreHit; [Resolved] - private DrumSampleContainer sampleContainer { get; set; } + private DrumSampleTriggerSource sampleTriggerSource { get; set; } public TaikoHalfDrum(bool flipped) { @@ -156,21 +157,19 @@ namespace osu.Game.Rulesets.Taiko.UI Drawable target = null; Drawable back = null; - var drumSample = sampleContainer.SampleAt(Time.Current); - if (action == CentreAction) { target = centreHit; back = centre; - drumSample.Centre?.Play(); + sampleTriggerSource.Play(HitType.Centre); } else if (action == RimAction) { target = rimHit; back = rim; - drumSample.Rim?.Play(); + sampleTriggerSource.Play(HitType.Rim); } if (target != null) @@ -201,5 +200,25 @@ namespace osu.Game.Rulesets.Taiko.UI { } } + + public class DrumSampleTriggerSource : GameplaySampleTriggerSource + { + public DrumSampleTriggerSource(HitObjectContainer hitObjectContainer) + : base(hitObjectContainer) + { + } + + public void Play(HitType hitType) + { + var hitObject = GetMostValidObject(); + + if (hitObject == null) + return; + + PlaySamples(new ISampleInfo[] { hitObject.SampleControlPoint.GetSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_CLAP : HitSampleInfo.HIT_NORMAL) }); + } + + public override void Play() => throw new InvalidOperationException(@"Use override with HitType parameter instead"); + } } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs index 0d9e08b8b7..d650cab729 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoPlayfield.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; -using osu.Game.Beatmaps.ControlPoints; using osu.Game.Graphics; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Judgements; @@ -27,8 +26,6 @@ namespace osu.Game.Rulesets.Taiko.UI { public class TaikoPlayfield : ScrollingPlayfield { - private readonly ControlPointInfo controlPoints; - /// /// Default height of a when inside a . /// @@ -56,11 +53,6 @@ namespace osu.Game.Rulesets.Taiko.UI private Container hitTargetOffsetContent; - public TaikoPlayfield(ControlPointInfo controlPoints) - { - this.controlPoints = controlPoints; - } - [BackgroundDependencyLoader] private void load(OsuColour colours) { @@ -131,7 +123,7 @@ namespace osu.Game.Rulesets.Taiko.UI Children = new Drawable[] { new SkinnableDrawable(new TaikoSkinComponent(TaikoSkinComponents.PlayfieldBackgroundLeft), _ => new PlayfieldBackgroundLeft()), - new InputDrum(controlPoints) + new InputDrum(HitObjectContainer) { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, From ef2b5e1c51d0fbcc4caece8588590375104a9b90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 15:29:47 +0900 Subject: [PATCH 619/961] Tidy up variable names and unused resolved properties --- .../UI/GameplaySampleTriggerSource.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index 015c85beb9..48905e7232 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -2,8 +2,6 @@ // 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.Audio; using osu.Game.Rulesets.Objects; @@ -27,20 +25,14 @@ namespace osu.Game.Rulesets.UI private readonly Container hitSounds; - [Resolved] - private DrawableRuleset drawableRuleset { get; set; } - public GameplaySampleTriggerSource(HitObjectContainer hitObjectContainer) { this.hitObjectContainer = hitObjectContainer; - InternalChildren = new Drawable[] + + InternalChild = hitSounds = new Container { - hitSounds = new Container - { - Name = "concurrent sample pool", - RelativeSizeAxes = Axes.Both, - Children = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()).ToArray() - }, + Name = "concurrent sample pool", + ChildrenEnumerable = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()) }; } @@ -74,10 +66,10 @@ namespace osu.Game.Rulesets.UI protected HitObject GetMostValidObject() { // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. - var nextObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; + var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. - if (nextObject == null) + if (hitObject == null) { // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). if (fallbackObject == null || fallbackObject.HitObject.StartTime < Time.Current || fallbackObject.Result?.IsHit == true) @@ -97,15 +89,15 @@ namespace osu.Game.Rulesets.UI fallbackObject ??= hitObjectContainer.Entries.FirstOrDefault(); } - nextObject = fallbackObject?.HitObject; + hitObject = fallbackObject?.HitObject; } - return nextObject; + return hitObject; } private SkinnableSound getNextSample() { - var hitSound = hitSounds[nextHitSoundIndex]; + SkinnableSound hitSound = hitSounds[nextHitSoundIndex]; // round robin over available samples to allow for concurrent playback. nextHitSoundIndex = (nextHitSoundIndex + 1) % max_concurrent_hitsounds; From fc85ae0e349b7f01b4087cdef76250ac160873d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 16:55:03 +0900 Subject: [PATCH 620/961] Add test coverage --- .../TestSceneGameplaySampleTriggerSource.cs | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs new file mode 100644 index 0000000000..c446a7efd1 --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -0,0 +1,135 @@ +// 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.Game.Audio; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Objects; +using osu.Game.Rulesets.Objects.Drawables; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.UI; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Gameplay +{ + public class TestSceneGameplaySampleTriggerSource : PlayerTestScene + { + private TestGameplaySampleTriggerSource sampleTriggerSource; + protected override Ruleset CreatePlayerRuleset() => new OsuRuleset(); + + private Beatmap beatmap; + + protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) + { + beatmap = new Beatmap + { + BeatmapInfo = new BeatmapInfo + { + BaseDifficulty = new BeatmapDifficulty { CircleSize = 6, SliderMultiplier = 3 }, + Ruleset = ruleset + } + }; + + const double start_offset = 8000; + const double spacing = 2000; + + double t = start_offset; + beatmap.HitObjects.AddRange(new[] + { + new HitCircle + { + // intentionally start objects a bit late so we can test the case of no alive objects. + StartTime = t += spacing, + Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) } + }, + new HitCircle + { + StartTime = t += spacing, + Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) } + }, + new HitCircle + { + StartTime = t += spacing, + Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) }, + SampleControlPoint = new SampleControlPoint { SampleBank = "soft" }, + }, + new HitCircle + { + StartTime = t += spacing, + Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) }, + SampleControlPoint = new SampleControlPoint { SampleBank = "soft" }, + }, + }); + + return beatmap; + } + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("Add trigger source", () => Player.HUDOverlay.Add(sampleTriggerSource = new TestGameplaySampleTriggerSource(Player.DrawableRuleset.Playfield.HitObjectContainer))); + } + + [Test] + public void TestCorrectHitObject() + { + HitObjectLifetimeEntry nextObjectEntry = null; + + AddUntilStep("no alive objects", () => getNextAliveObject() == null); + + AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); + + AddUntilStep("get next object", () => + { + var nextDrawableObject = getNextAliveObject(); + + if (nextDrawableObject != null) + { + nextObjectEntry = nextDrawableObject.Entry; + InputManager.MoveMouseTo(nextDrawableObject.ScreenSpaceDrawQuad.Centre); + return true; + } + + return false; + }); + + AddUntilStep("hit first hitobject", () => + { + InputManager.Click(MouseButton.Left); + return nextObjectEntry.Result.HasResult; + }); + + AddAssert("check correct object after hit", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[1]); + + AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[2]); + AddUntilStep("check correct object after miss", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + + AddUntilStep("no alive objects", () => getNextAliveObject() == null); + AddAssert("check correct object after none alive", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[3]); + } + + private DrawableHitObject getNextAliveObject() => + Player.DrawableRuleset.Playfield.HitObjectContainer.AliveObjects.FirstOrDefault(); + + [Test] + public void TestSampleTriggering() + { + AddRepeatStep("trigger sample", () => sampleTriggerSource.Play(), 10); + } + + public class TestGameplaySampleTriggerSource : GameplaySampleTriggerSource + { + public TestGameplaySampleTriggerSource(HitObjectContainer hitObjectContainer) + : base(hitObjectContainer) + { + } + + public new HitObject GetMostValidObject() => base.GetMostValidObject(); + } + } +} From ccfff50c6f18c5a9b790e02e08cb9b16c3b6bac8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 16:55:34 +0900 Subject: [PATCH 621/961] Apply fixes in line with issues found during testing I was trying to be too smart with caching, but if the `Play` method was not called often enough it would have a recent reference. Unfortunately this requires a separate query to `Entries`, but is also a special case (no future hitobjects). This also removes the time-based checks (result status alone should be all we care about). --- .../UI/GameplaySampleTriggerSource.cs | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index 48905e7232..bceb5996b9 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -66,27 +66,23 @@ namespace osu.Game.Rulesets.UI protected HitObject GetMostValidObject() { // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. - var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.HitObject.StartTime > Time.Current)?.HitObject; + var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.IsHit != true)?.HitObject; // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. if (hitObject == null) { // This lookup can be skipped if the last entry is still valid (in the future and not yet hit). - if (fallbackObject == null || fallbackObject.HitObject.StartTime < Time.Current || fallbackObject.Result?.IsHit == true) + if (fallbackObject == null || fallbackObject.Result?.HasResult == true) { // We need to use lifetime entries to find the next object (we can't just use `hitObjectContainer.Objects` due to pooling - it may even be empty). // If required, we can make this lookup more efficient by adding support to get next-future-entry in LifetimeEntryManager. - var lookup = hitObjectContainer.Entries - .Where(e => e.Result?.HasResult != true && e.HitObject.StartTime > Time.Current) - .OrderBy(e => e.HitObject.StartTime) - .FirstOrDefault(); + fallbackObject = hitObjectContainer.Entries + .Where(e => e.Result?.HasResult != true) + .OrderBy(e => e.HitObject.StartTime) + .FirstOrDefault(); - // If the lookup failed, use the previously resolved lookup (we still want to play a sound, and it is still likely the most valid result). - if (lookup != null) - fallbackObject = lookup; - - // If we still can't find anything, just play whatever we can to get a sound out. - fallbackObject ??= hitObjectContainer.Entries.FirstOrDefault(); + // In the case there are no unjudged objects, the last hit object should be used instead. + fallbackObject ??= hitObjectContainer.Entries.LastOrDefault(); } hitObject = fallbackObject?.HitObject; From fd78d0440bfca93e6313e546bd91d5f5aec3794d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 17:00:32 +0900 Subject: [PATCH 622/961] Update missed conditional --- osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index bceb5996b9..ac2067a913 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.UI protected HitObject GetMostValidObject() { // The most optimal lookup case we have is when an object is alive. There are usually very few alive objects so there's no drawbacks in attempting this lookup each time. - var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.IsHit != true)?.HitObject; + var hitObject = hitObjectContainer.AliveObjects.FirstOrDefault(h => h.Result?.HasResult != true)?.HitObject; // In the case a next object isn't available in drawable form, we need to do a somewhat expensive traversal to get a valid sound to play. if (hitObject == null) From 599145b46aaaf543146307f575ec2e0632b7f3ac Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 11:29:48 +0300 Subject: [PATCH 623/961] Stop clocks when removing them from sync manager --- .../OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs index cf0dfbb585..b8f47c16ff 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/CatchUpSyncManager.cs @@ -61,7 +61,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate playerClocks.Add(clock); } - public void RemovePlayerClock(ISpectatorPlayerClock clock) => playerClocks.Remove(clock); + public void RemovePlayerClock(ISpectatorPlayerClock clock) + { + playerClocks.Remove(clock); + clock.Stop(); + } protected override void Update() { From 196c74fce87048c33e6c3ed1ee099b870438adb3 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 11:30:13 +0300 Subject: [PATCH 624/961] Gray out and remove player clock when users stop playing --- .../Multiplayer/Spectate/MultiSpectatorScreen.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs index d10917259d..bf7c738882 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; using osu.Game.Online.Multiplayer; using osu.Game.Online.Spectator; using osu.Game.Screens.Play; @@ -32,6 +33,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate /// public bool AllPlayersLoaded => instances.All(p => p?.PlayerLoaded == true); + [Resolved] + private OsuColour colours { get; set; } + [Resolved] private SpectatorClient spectatorClient { get; set; } @@ -215,6 +219,11 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate protected override void EndGameplay(int userId) { RemoveUser(userId); + + var instance = instances.Single(i => i.UserId == userId); + + instance.FadeColour(colours.Gray4, 400, Easing.OutQuint); + syncManager.RemovePlayerClock(instance.GameplayClock); leaderboard.RemoveClock(userId); } From 13acdb5f19137d5868ac946885ed29a0e3a9e6f9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 11:30:37 +0300 Subject: [PATCH 625/961] Add test coverage --- .../TestSceneMultiSpectatorScreen.cs | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 18e4a6c575..1c198c11aa 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -19,6 +20,7 @@ using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Tests.Visual.Multiplayer { @@ -314,6 +316,25 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("player 2 playing from correct point in time", () => getPlayer(PLAYER_2_ID).ChildrenOfType().Single().FrameStableClock.CurrentTime > 30000); } + [Test] + public void TestPlayersLeaveWhileSpectating() + { + start(Enumerable.Range(PLAYER_1_ID, 8).ToArray()); + sendFrames(Enumerable.Range(PLAYER_1_ID, 8).ToArray(), 300); + + loadSpectateScreen(); + + for (int i = 7; i >= 0; i--) + { + var id = PLAYER_1_ID + i; + + end(new[] { id }); + AddUntilStep("player area grayed", () => getInstance(id).Colour != Color4.White); + AddUntilStep("score quit set", () => getLeaderboardScore(id).HasQuit.Value); + sendFrames(Enumerable.Range(PLAYER_1_ID, i).ToArray(), 300); + } + } + private void loadSpectateScreen(bool waitForPlayerLoad = true) { AddStep("load screen", () => @@ -333,10 +354,31 @@ namespace osu.Game.Tests.Visual.Multiplayer { foreach (int id in userIds) { - OnlinePlayDependencies.Client.AddUser(new User { Id = id }, true); + var user = new MultiplayerRoomUser(id) + { + User = new User { Id = id }, + }; + OnlinePlayDependencies.Client.AddUser(user.User, true); SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId); - playingUsers.Add(new MultiplayerRoomUser(id)); + + playingUsers.Add(user); + } + }); + } + + private void end(int[] userIds) + { + AddStep("end play", () => + { + foreach (int id in userIds) + { + var user = playingUsers.Single(u => u.UserID == id); + + OnlinePlayDependencies.Client.RemoveUser(user.User.AsNonNull()); + SpectatorClient.EndPlay(id); + + playingUsers.Remove(user); } }); } @@ -374,5 +416,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private Player getPlayer(int userId) => getInstance(userId).ChildrenOfType().Single(); private PlayerArea getInstance(int userId) => spectatorScreen.ChildrenOfType().Single(p => p.UserId == userId); + + private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType().Single(s => s.User?.Id == userId); } } From 7e6e2a7e292b5030739c07b342c46d0f68118323 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 17:39:06 +0900 Subject: [PATCH 626/961] Remove unused assignment --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index c446a7efd1..3e0a937ffa 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Gameplay }, new HitCircle { - StartTime = t += spacing, + StartTime = t + spacing, Samples = new[] { new HitSampleInfo(HitSampleInfo.HIT_WHISTLE) }, SampleControlPoint = new SampleControlPoint { SampleBank = "soft" }, }, From c32168c61f2d358ca88173a9f74bdccafbf699ab Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 17:03:33 +0300 Subject: [PATCH 627/961] Add failing test case --- .../Editing/TestSceneEditorScreenModes.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.cs new file mode 100644 index 0000000000..98d8a41674 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorScreenModes.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 System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Testing; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Components.Menus; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneEditorScreenModes : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); + + [Test] + public void TestSwitchScreensInstantaneously() + { + AddStep("switch between all screens at once", () => + { + foreach (var screen in Enum.GetValues(typeof(EditorScreenMode)).Cast()) + Editor.ChildrenOfType().Single().Mode.Value = screen; + }); + } + } +} From 3ad0b529fbdeff6297f6a0ba8be73255a32bd895 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 16:58:06 +0300 Subject: [PATCH 628/961] Make `EditorScreen` inherit from `VisibilityContainer` rather than unsafe transforms --- osu.Game/Screens/Edit/Editor.cs | 12 +++++------- osu.Game/Screens/Edit/EditorScreen.cs | 15 +++++++++------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index e8d919311b..57c78f3c65 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -605,19 +605,14 @@ namespace osu.Game.Screens.Edit { var lastScreen = currentScreen; - lastScreen? - .ScaleTo(0.98f, 200, Easing.OutQuint) - .FadeOut(200, Easing.OutQuint); + lastScreen?.Hide(); try { if ((currentScreen = screenContainer.SingleOrDefault(s => s.Type == e.NewValue)) != null) { screenContainer.ChangeChildDepth(currentScreen, lastScreen?.Depth + 1 ?? 0); - - currentScreen - .ScaleTo(1, 200, Easing.OutQuint) - .FadeIn(200, Easing.OutQuint); + currentScreen.Show(); return; } @@ -650,7 +645,10 @@ namespace osu.Game.Screens.Edit LoadComponentAsync(currentScreen, newScreen => { if (newScreen == currentScreen) + { screenContainer.Add(newScreen); + newScreen.Show(); + } }); } finally diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 7fbb6a8ca0..d7fe5207d0 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -10,7 +10,7 @@ namespace osu.Game.Screens.Edit /// /// TODO: eventually make this inherit Screen and add a local screen stack inside the Editor. /// - public abstract class EditorScreen : Container + public abstract class EditorScreen : VisibilityContainer { [Resolved] protected EditorBeatmap EditorBeatmap { get; private set; } @@ -31,13 +31,16 @@ namespace osu.Game.Screens.Edit InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; } - protected override void LoadComplete() + protected override void PopIn() { - base.LoadComplete(); + this.ScaleTo(1f, 200, Easing.OutQuint) + .FadeIn(200, Easing.OutQuint); + } - this.FadeTo(0) - .Then() - .FadeTo(1f, 250, Easing.OutQuint); + protected override void PopOut() + { + this.ScaleTo(0.98f, 200, Easing.OutQuint) + .FadeOut(200, Easing.OutQuint); } } } From f9b25a01590ac076ac3dfc98eda9e7dab552d359 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 15:09:57 +0300 Subject: [PATCH 629/961] Add test case for switching to each screen in editor test scenes --- osu.Game/Tests/Visual/EditorTestScene.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a393802309..2644daa3a4 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -3,6 +3,7 @@ using System.Linq; using JetBrains.Annotations; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.IO.Stores; @@ -28,6 +29,9 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } + [Resolved] + private SkinManager skins { get; set; } + /// /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . /// @@ -57,6 +61,12 @@ namespace osu.Game.Tests.Visual AddStep("get clock", () => EditorClock = Editor.ChildrenOfType().Single()); } + [Test] + public void TestLegacySkin() + { + AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.Info); + } + protected virtual void LoadEditor() { LoadScreen(Editor = CreateEditor()); From b4d6495f99a60194a8609cf3d35d048166001b03 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 15:03:20 +0300 Subject: [PATCH 630/961] Fix editor skin providing container not providing playable beatmap --- osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs index 27563b5a0f..decfa879a8 100644 --- a/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs +++ b/osu.Game/Screens/Edit/EditorSkinProvidingContainer.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit private readonly EditorBeatmapSkin? beatmapSkin; public EditorSkinProvidingContainer(EditorBeatmap editorBeatmap) - : base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap, editorBeatmap.BeatmapSkin) + : base(editorBeatmap.PlayableBeatmap.BeatmapInfo.Ruleset.CreateInstance(), editorBeatmap.PlayableBeatmap, editorBeatmap.BeatmapSkin) { beatmapSkin = editorBeatmap.BeatmapSkin; } From 998abcbf31350ae033c6159904365337196cb0a9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 18:25:31 +0300 Subject: [PATCH 631/961] Replace occurences of `Enumerable.Range(PLAYER_1_ID, ...)` with a method --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 1c198c11aa..97c992e8ec 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestGeneral() { - int[] userIds = Enumerable.Range(0, 4).Select(i => PLAYER_1_ID + i).ToArray(); + int[] userIds = getPlayerIds(4); start(userIds); loadSpectateScreen(); @@ -319,19 +319,19 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestPlayersLeaveWhileSpectating() { - start(Enumerable.Range(PLAYER_1_ID, 8).ToArray()); - sendFrames(Enumerable.Range(PLAYER_1_ID, 8).ToArray(), 300); + start(getPlayerIds(8)); + sendFrames(getPlayerIds(8), 300); loadSpectateScreen(); - for (int i = 7; i >= 0; i--) + for (int count = 7; count >= 0; count--) { - var id = PLAYER_1_ID + i; + var id = PLAYER_1_ID + count; end(new[] { id }); AddUntilStep("player area grayed", () => getInstance(id).Colour != Color4.White); AddUntilStep("score quit set", () => getLeaderboardScore(id).HasQuit.Value); - sendFrames(Enumerable.Range(PLAYER_1_ID, i).ToArray(), 300); + sendFrames(getPlayerIds(count), 300); } } @@ -418,5 +418,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private PlayerArea getInstance(int userId) => spectatorScreen.ChildrenOfType().Single(p => p.UserId == userId); private GameplayLeaderboardScore getLeaderboardScore(int userId) => spectatorScreen.ChildrenOfType().Single(s => s.User?.Id == userId); + + private int[] getPlayerIds(int count) => Enumerable.Range(PLAYER_1_ID, count).ToArray(); } } From 5acaafa7089f28104c53685bf9db9c505d8c3890 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Wed, 25 Aug 2021 18:28:23 +0300 Subject: [PATCH 632/961] Make `end` accept one user ID rather than unnecessarily an array --- .../TestSceneMultiSpectatorScreen.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 97c992e8ec..c3be5c56ef 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -328,7 +328,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { var id = PLAYER_1_ID + count; - end(new[] { id }); + end(id); AddUntilStep("player area grayed", () => getInstance(id).Colour != Color4.White); AddUntilStep("score quit set", () => getLeaderboardScore(id).HasQuit.Value); sendFrames(getPlayerIds(count), 300); @@ -367,19 +367,16 @@ namespace osu.Game.Tests.Visual.Multiplayer }); } - private void end(int[] userIds) + private void end(int userId) { - AddStep("end play", () => + AddStep($"end play for {userId}", () => { - foreach (int id in userIds) - { - var user = playingUsers.Single(u => u.UserID == id); + var user = playingUsers.Single(u => u.UserID == userId); - OnlinePlayDependencies.Client.RemoveUser(user.User.AsNonNull()); - SpectatorClient.EndPlay(id); + OnlinePlayDependencies.Client.RemoveUser(user.User.AsNonNull()); + SpectatorClient.EndPlay(userId); - playingUsers.Remove(user); - } + playingUsers.Remove(user); }); } From 956e3c554bd420371fa9b7d3242643184fc6efd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 00:50:55 +0900 Subject: [PATCH 633/961] Avoid skip overlay attempting to show when it is already invalid --- osu.Game/Screens/Play/SkipOverlay.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 4a74fa1d4f..dd6ba3c2f1 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -37,6 +37,8 @@ namespace osu.Game.Screens.Play private FadeContainer fadeContainer; private double displayTime; + private bool isClickable; + [Resolved] private GameplayClock gameplayClock { get; set; } @@ -124,17 +126,18 @@ namespace osu.Game.Screens.Play { base.Update(); - var progress = fadeOutBeginTime <= displayTime ? 1 : Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); + double progress = fadeOutBeginTime <= displayTime ? 1 : Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); - button.Enabled.Value = progress > 0; - buttonContainer.State.Value = progress > 0 ? Visibility.Visible : Visibility.Hidden; + isClickable = progress > 0; + button.Enabled.Value = isClickable; + buttonContainer.State.Value = isClickable ? Visibility.Visible : Visibility.Hidden; } protected override bool OnMouseMove(MouseMoveEvent e) { - if (!e.HasAnyButtonPressed) + if (isClickable && !e.HasAnyButtonPressed) fadeContainer.Show(); return base.OnMouseMove(e); From b1a261c9029e1b6e5cf0b92da39a5fc3d64c4213 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 01:02:27 +0900 Subject: [PATCH 634/961] Avoid using scheduled delegates at all for skip overload input handling --- osu.Game/Screens/Play/SkipOverlay.cs | 46 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index dd6ba3c2f1..71a70991d2 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Containers; @@ -120,6 +119,8 @@ namespace osu.Game.Screens.Play button.Action = () => RequestSkip?.Invoke(); displayTime = gameplayClock.CurrentTime; + + fadeContainer.TriggerShow(); } protected override void Update() @@ -138,7 +139,7 @@ namespace osu.Game.Screens.Play protected override bool OnMouseMove(MouseMoveEvent e) { if (isClickable && !e.HasAnyButtonPressed) - fadeContainer.Show(); + fadeContainer.TriggerShow(); return base.OnMouseMove(e); } @@ -167,34 +168,45 @@ namespace osu.Game.Screens.Play public event Action StateChanged; private Visibility state; - private ScheduledDelegate scheduledHide; + private double? nextHideTime; public override bool IsPresent => true; + public void TriggerShow() + { + Show(); + + if (!IsHovered && !IsDragged) + nextHideTime = Time.Current + 1000; + else + nextHideTime = null; + } + + protected override void Update() + { + base.Update(); + + if (nextHideTime != null && nextHideTime <= Time.Current) + { + Hide(); + nextHideTime = null; + } + } + public Visibility State { get => state; set { - bool stateChanged = value != state; + if (value == state) + return; state = value; - scheduledHide?.Cancel(); - switch (state) { case Visibility.Visible: - // we may be triggered to become visible multiple times but we only want to transform once. - if (stateChanged) - this.FadeIn(500, Easing.OutExpo); - - if (!IsHovered && !IsDragged) - { - using (BeginDelayedSequence(1000)) - scheduledHide = Schedule(Hide); - } - + this.FadeIn(500, Easing.OutExpo); break; case Visibility.Hidden: @@ -215,7 +227,7 @@ namespace osu.Game.Screens.Play protected override bool OnMouseDown(MouseDownEvent e) { Show(); - scheduledHide?.Cancel(); + nextHideTime = null; return true; } From 6dcd9427ac809999a5357f075a00fa41cb40c141 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 01:42:57 +0900 Subject: [PATCH 635/961] Remove bindable usage in `PathControlPoint` This is quite a breaking change, but I think it is beneficial due to the large amount of usage of this class. I originally intended just to remove the allocations of the two delegates handling the `Changed` flow internally, but as nothing was really using the bindables for anything more than a general "point has changed" case, this felt like a better direction. --- .../JuiceStreamPathTest.cs | 8 +- .../Beatmaps/CatchBeatmapProcessor.cs | 2 +- .../Blueprints/Components/EditablePath.cs | 2 +- .../Edit/CatchSelectionHandler.cs | 2 +- .../Mods/CatchModMirror.cs | 4 +- .../Objects/JuiceStream.cs | 2 +- .../Objects/JuiceStreamPath.cs | 2 +- .../TestScenePathControlPointVisualiser.cs | 4 +- .../TestSceneSliderPlacementBlueprint.cs | 4 +- .../TestSceneSliderSelectionBlueprint.cs | 2 +- .../PathControlPointConnectionPiece.cs | 4 +- .../Components/PathControlPointPiece.cs | 34 ++-- .../Components/PathControlPointVisualiser.cs | 4 +- .../Sliders/SliderPlacementBlueprint.cs | 12 +- .../Sliders/SliderSelectionBlueprint.cs | 14 +- .../Edit/OsuSelectionHandler.cs | 20 +-- osu.Game.Rulesets.Osu/Objects/Slider.cs | 2 +- .../Utils/OsuHitObjectGenerationUtils.cs | 8 +- .../Formats/LegacyBeatmapDecoderTest.cs | 152 +++++++++--------- .../Visual/Gameplay/TestSceneSliderPath.cs | 18 +-- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 16 +- .../Objects/Legacy/ConvertHitObjectParser.cs | 12 +- osu.Game/Rulesets/Objects/PathControlPoint.cs | 41 +++-- osu.Game/Rulesets/Objects/SliderPath.cs | 8 +- .../Rulesets/Objects/SliderPathExtensions.cs | 14 +- 25 files changed, 203 insertions(+), 188 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs index 5e4b6d9e1a..8fa96fb8c9 100644 --- a/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/JuiceStreamPathTest.cs @@ -154,7 +154,7 @@ namespace osu.Game.Rulesets.Catch.Tests } while (rng.Next(2) != 0); int length = sliderPath.ControlPoints.Count - start + 1; - sliderPath.ControlPoints[start].Type.Value = length <= 2 ? PathType.Linear : length == 3 ? PathType.PerfectCurve : PathType.Bezier; + sliderPath.ControlPoints[start].Type = length <= 2 ? PathType.Linear : length == 3 ? PathType.PerfectCurve : PathType.Bezier; } while (rng.Next(3) != 0); if (rng.Next(5) == 0) @@ -210,13 +210,13 @@ namespace osu.Game.Rulesets.Catch.Tests path.ConvertToSliderPath(sliderPath, sliderStartY); Assert.That(sliderPath.Distance, Is.EqualTo(path.Distance).Within(1e-3)); - Assert.That(sliderPath.ControlPoints[0].Position.Value.X, Is.EqualTo(path.Vertices[0].X)); + Assert.That(sliderPath.ControlPoints[0].Position.X, Is.EqualTo(path.Vertices[0].X)); assertInvariants(path.Vertices, true); foreach (var point in sliderPath.ControlPoints) { - Assert.That(point.Type.Value, Is.EqualTo(PathType.Linear).Or.Null); - Assert.That(sliderStartY + point.Position.Value.Y, Is.InRange(0, JuiceStreamPath.OSU_PLAYFIELD_HEIGHT)); + Assert.That(point.Type, Is.EqualTo(PathType.Linear).Or.Null); + Assert.That(sliderStartY + point.Position.Y, Is.InRange(0, JuiceStreamPath.OSU_PLAYFIELD_HEIGHT)); } for (int i = 0; i < 10; i++) diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs index 3a5322ce82..a891ec6c0a 100644 --- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps case JuiceStream juiceStream: // Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead. - lastPosition = juiceStream.OriginalX + juiceStream.Path.ControlPoints[^1].Position.Value.X; + lastPosition = juiceStream.OriginalX + juiceStream.Path.ControlPoints[^1].Position.X; // Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead. lastStartTime = juiceStream.StartTime; diff --git a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs index 8aaeef045f..1a43a10c81 100644 --- a/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs +++ b/osu.Game.Rulesets.Catch/Edit/Blueprints/Components/EditablePath.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints.Components path.ConvertFromSliderPath(sliderPath); // If the original slider path has non-linear type segments, resample the vertices at nested hit object times to reduce the number of vertices. - if (sliderPath.ControlPoints.Any(p => p.Type.Value != null && p.Type.Value != PathType.Linear)) + if (sliderPath.ControlPoints.Any(p => p.Type != null && p.Type != PathType.Linear)) { path.ResampleVertices(hitObject.NestedHitObjects .Skip(1).TakeWhile(h => !(h is Fruit)) // Only droplets in the first span are used. diff --git a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs index 36072d7fcb..8cb0804ab7 100644 --- a/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs +++ b/osu.Game.Rulesets.Catch/Edit/CatchSelectionHandler.cs @@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Catch.Edit juiceStream.OriginalX = selectionRange.GetFlippedPosition(juiceStream.OriginalX); foreach (var point in juiceStream.Path.ControlPoints) - point.Position.Value *= new Vector2(-1, 1); + point.Position *= new Vector2(-1, 1); EditorBeatmap.Update(juiceStream); return true; diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs index 932c8cad85..a97e940a64 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModMirror.cs @@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Catch.Mods /// private static void mirrorJuiceStreamPath(JuiceStream juiceStream) { - var controlPoints = juiceStream.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + var controlPoints = juiceStream.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); foreach (var point in controlPoints) - point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); + point.Position = new Vector2(-point.Position.X, point.Position.Y); juiceStream.Path = new SliderPath(controlPoints, juiceStream.Path.ExpectedDistance.Value); } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 3088d024d1..a8ad34fcbe 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Catch.Objects if (value != null) { - path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value))); + path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type))); path.ExpectedDistance.Value = value.ExpectedDistance.Value; } } diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStreamPath.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStreamPath.cs index f1cdb39e91..7207833fe6 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStreamPath.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStreamPath.cs @@ -234,7 +234,7 @@ namespace osu.Game.Rulesets.Catch.Objects for (int i = 1; i < vertices.Count; i++) { - sliderPath.ControlPoints[^1].Type.Value = PathType.Linear; + sliderPath.ControlPoints[^1].Type = PathType.Linear; float deltaX = vertices[i].X - lastPosition.X; double length = vertices[i].Distance - currentDistance; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs index 35b79aa8ac..53a9f06eee 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor AddAssert("last connection displayed", () => { - var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position.Value == new Vector2(300)); + var lastConnection = visualiser.Connections.Last(c => c.ControlPoint.Position == new Vector2(300)); return lastConnection.DrawWidth > 50; }); } @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private void assertControlPointPathType(int controlPointIndex, PathType? type) { - AddAssert($"point {controlPointIndex} is {type}", () => slider.Path.ControlPoints[controlPointIndex].Type.Value == type); + AddAssert($"point {controlPointIndex} is {type}", () => slider.Path.ControlPoints[controlPointIndex].Type == type); } private void addContextMenuItemStep(string contextMenuText) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs index 8235e1bc79..e724015905 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderPlacementBlueprint.cs @@ -385,10 +385,10 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor private void assertControlPointCount(int expected) => AddAssert($"has {expected} control points", () => getSlider().Path.ControlPoints.Count == expected); - private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => getSlider().Path.ControlPoints[index].Type.Value == type); + private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => getSlider().Path.ControlPoints[index].Type == type); private void assertControlPointPosition(int index, Vector2 position) => - AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, getSlider().Path.ControlPoints[index].Position.Value, 1)); + AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, getSlider().Path.ControlPoints[index].Position, 1)); private Slider getSlider() => HitObjectContainer.Count > 0 ? ((DrawableSlider)HitObjectContainer[0]).HitObject : null; diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs index 0d828a79c8..cc43eb3852 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderSelectionBlueprint.cs @@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { AddStep($"move mouse to control point {index}", () => { - Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position.Value; + Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position; InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position)); }); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs index eb7011e8b0..d66c9ea4bf 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointConnectionPiece.cs @@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// private void updateConnectingPath() { - Position = slider.StackedPosition + ControlPoint.Position.Value; + Position = slider.StackedPosition + ControlPoint.Position; path.ClearVertices(); @@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components return; path.AddVertex(Vector2.Zero); - path.AddVertex(slider.Path.ControlPoints[nextIndex].Position.Value - ControlPoint.Position.Value); + path.AddVertex(slider.Path.ControlPoints[nextIndex].Position - ControlPoint.Position); path.OriginPosition = path.PositionInBoundingBox(Vector2.Zero); } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs index 5b476526c9..2cc95e1891 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointPiece.cs @@ -53,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private IBindable sliderPosition; private IBindable sliderScale; - private IBindable controlPointPosition; public PathControlPointPiece(Slider slider, PathControlPoint controlPoint) { @@ -69,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components updatePathType(); }); - controlPoint.Type.BindValueChanged(_ => updateMarkerDisplay()); + controlPoint.Changed += updateMarkerDisplay; Origin = Anchor.Centre; AutoSizeAxes = Axes.Both; @@ -117,9 +116,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components sliderPosition = slider.PositionBindable.GetBoundCopy(); sliderPosition.BindValueChanged(_ => updateMarkerDisplay()); - controlPointPosition = ControlPoint.Position.GetBoundCopy(); - controlPointPosition.BindValueChanged(_ => updateMarkerDisplay()); - sliderScale = slider.ScaleBindable.GetBoundCopy(); sliderScale.BindValueChanged(_ => updateMarkerDisplay()); @@ -174,8 +170,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components if (e.Button == MouseButton.Left) { - dragStartPosition = ControlPoint.Position.Value; - dragPathType = PointsInSegment[0].Type.Value; + dragStartPosition = ControlPoint.Position; + dragPathType = PointsInSegment[0].Type; changeHandler?.BeginChange(); return true; @@ -186,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components protected override void OnDrag(DragEvent e) { - Vector2[] oldControlPoints = slider.Path.ControlPoints.Select(cp => cp.Position.Value).ToArray(); + Vector2[] oldControlPoints = slider.Path.ControlPoints.Select(cp => cp.Position).ToArray(); var oldPosition = slider.Position; var oldStartTime = slider.StartTime; @@ -202,15 +198,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components // Since control points are relative to the position of the slider, they all need to be offset backwards by the delta for (int i = 1; i < slider.Path.ControlPoints.Count; i++) - slider.Path.ControlPoints[i].Position.Value -= movementDelta; + slider.Path.ControlPoints[i].Position -= movementDelta; } else - ControlPoint.Position.Value = dragStartPosition + (e.MousePosition - e.MouseDownPosition); + ControlPoint.Position = dragStartPosition + (e.MousePosition - e.MouseDownPosition); if (!slider.Path.HasValidLength) { for (var i = 0; i < slider.Path.ControlPoints.Count; i++) - slider.Path.ControlPoints[i].Position.Value = oldControlPoints[i]; + slider.Path.ControlPoints[i].Position = oldControlPoints[i]; slider.Position = oldPosition; slider.StartTime = oldStartTime; @@ -218,7 +214,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components } // Maintain the path type in case it got defaulted to bezier at some point during the drag. - PointsInSegment[0].Type.Value = dragPathType; + PointsInSegment[0].Type = dragPathType; } protected override void OnDragEnd(DragEndEvent e) => changeHandler?.EndChange(); @@ -230,19 +226,19 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// private void updatePathType() { - if (ControlPoint.Type.Value != PathType.PerfectCurve) + if (ControlPoint.Type != PathType.PerfectCurve) return; if (PointsInSegment.Count > 3) - ControlPoint.Type.Value = PathType.Bezier; + ControlPoint.Type = PathType.Bezier; if (PointsInSegment.Count != 3) return; - ReadOnlySpan points = PointsInSegment.Select(p => p.Position.Value).ToArray(); + ReadOnlySpan points = PointsInSegment.Select(p => p.Position).ToArray(); RectangleF boundingBox = PathApproximator.CircularArcBoundingBox(points); if (boundingBox.Width >= 640 || boundingBox.Height >= 480) - ControlPoint.Type.Value = PathType.Bezier; + ControlPoint.Type = PathType.Bezier; } /// @@ -250,7 +246,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components /// private void updateMarkerDisplay() { - Position = slider.StackedPosition + ControlPoint.Position.Value; + Position = slider.StackedPosition + ControlPoint.Position; markerRing.Alpha = IsSelected.Value ? 1 : 0; @@ -265,7 +261,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private Color4 getColourFromNodeType() { - if (!(ControlPoint.Type.Value is PathType pathType)) + if (!(ControlPoint.Type is PathType pathType)) return colours.Yellow; switch (pathType) @@ -284,6 +280,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components } } - public LocalisableString TooltipText => ControlPoint.Type.Value.ToString() ?? string.Empty; + public LocalisableString TooltipText => ControlPoint.Type.ToString() ?? string.Empty; } } diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index 5bbdf9688f..ac1953c632 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -173,12 +173,12 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components int thirdPointIndex = indexInSegment + 2; if (piece.PointsInSegment.Count > thirdPointIndex + 1) - piece.PointsInSegment[thirdPointIndex].Type.Value = piece.PointsInSegment[0].Type.Value; + piece.PointsInSegment[thirdPointIndex].Type = piece.PointsInSegment[0].Type; break; } - piece.ControlPoint.Type.Value = type; + piece.ControlPoint.Type = type; } [Resolved(CanBeNull = true)] diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 8b20df9a68..b9e4ed6fcb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -108,7 +108,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders Debug.Assert(lastPoint != null); segmentStart = lastPoint; - segmentStart.Type.Value = PathType.Linear; + segmentStart.Type = PathType.Linear; currentSegmentLength = 1; } @@ -153,15 +153,15 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { case 1: case 2: - segmentStart.Type.Value = PathType.Linear; + segmentStart.Type = PathType.Linear; break; case 3: - segmentStart.Type.Value = PathType.PerfectCurve; + segmentStart.Type = PathType.PerfectCurve; break; default: - segmentStart.Type.Value = PathType.Bezier; + segmentStart.Type = PathType.Bezier; break; } } @@ -173,7 +173,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders // The cursor does not overlap a previous control point, so it can be added if not already existing. if (cursor == null) { - HitObject.Path.ControlPoints.Add(cursor = new PathControlPoint { Position = { Value = Vector2.Zero } }); + HitObject.Path.ControlPoints.Add(cursor = new PathControlPoint { Position = Vector2.Zero }); // The path type should be adjusted in the progression of updatePathType() (Linear -> PC -> Bezier). currentSegmentLength++; @@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders } // Update the cursor position. - cursor.Position.Value = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position; + cursor.Position = ToLocalSpace(inputManager.CurrentState.Mouse.Position) - HitObject.Position; } else if (cursor != null) { diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs index e810d2fe0c..89724876fa 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderSelectionBlueprint.cs @@ -161,7 +161,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { Debug.Assert(placementControlPointIndex != null); - HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position.Value = e.MousePosition - HitObject.Position; + HitObject.Path.ControlPoints[placementControlPointIndex.Value].Position = e.MousePosition - HitObject.Position; } protected override void OnDragEnd(DragEndEvent e) @@ -182,7 +182,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders for (int i = 0; i < controlPoints.Count - 1; i++) { - float dist = new Line(controlPoints[i].Position.Value, controlPoints[i + 1].Position.Value).DistanceToPoint(position); + float dist = new Line(controlPoints[i].Position, controlPoints[i + 1].Position).DistanceToPoint(position); if (dist < minDistance) { @@ -192,7 +192,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders } // Move the control points from the insertion index onwards to make room for the insertion - controlPoints.Insert(insertionIndex, new PathControlPoint { Position = { Value = position } }); + controlPoints.Insert(insertionIndex, new PathControlPoint { Position = position }); return insertionIndex; } @@ -207,8 +207,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders { // The first control point in the slider must have a type, so take it from the previous "first" one // Todo: Should be handled within SliderPath itself - if (c == controlPoints[0] && controlPoints.Count > 1 && controlPoints[1].Type.Value == null) - controlPoints[1].Type.Value = controlPoints[0].Type.Value; + if (c == controlPoints[0] && controlPoints.Count > 1 && controlPoints[1].Type == null) + controlPoints[1].Type = controlPoints[0].Type; controlPoints.Remove(c); } @@ -222,9 +222,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders // The path will have a non-zero offset if the head is removed, but sliders don't support this behaviour since the head is positioned at the slider's position // So the slider needs to be offset by this amount instead, and all control points offset backwards such that the path is re-positioned at (0, 0) - Vector2 first = controlPoints[0].Position.Value; + Vector2 first = controlPoints[0].Position; foreach (var c in controlPoints) - c.Position.Value -= first; + c.Position -= first; HitObject.Position += first; } diff --git a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs index 358a44e0e6..4a57d36eb4 100644 --- a/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs +++ b/osu.Game.Rulesets.Osu/Edit/OsuSelectionHandler.cs @@ -98,9 +98,9 @@ namespace osu.Game.Rulesets.Osu.Edit { foreach (var point in slider.Path.ControlPoints) { - point.Position.Value = new Vector2( - (direction == Direction.Horizontal ? -1 : 1) * point.Position.Value.X, - (direction == Direction.Vertical ? -1 : 1) * point.Position.Value.Y + point.Position = new Vector2( + (direction == Direction.Horizontal ? -1 : 1) * point.Position.X, + (direction == Direction.Vertical ? -1 : 1) * point.Position.Y ); } } @@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Edit if (h is IHasPath path) { foreach (var point in path.Path.ControlPoints) - point.Position.Value = RotatePointAroundOrigin(point.Position.Value, Vector2.Zero, delta); + point.Position = RotatePointAroundOrigin(point.Position, Vector2.Zero, delta); } } @@ -163,9 +163,9 @@ namespace osu.Game.Rulesets.Osu.Edit private void scaleSlider(Slider slider, Vector2 scale) { - referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type.Value).ToList(); + referencePathTypes ??= slider.Path.ControlPoints.Select(p => p.Type).ToList(); - Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position.Value)); + Quad sliderQuad = GetSurroundingQuad(slider.Path.ControlPoints.Select(p => p.Position)); // Limit minimum distance between control points after scaling to almost 0. Less than 0 causes the slider to flip, exactly 0 causes a crash through division by 0. scale = Vector2.ComponentMax(new Vector2(Precision.FLOAT_EPSILON), sliderQuad.Size + scale) - sliderQuad.Size; @@ -178,13 +178,13 @@ namespace osu.Game.Rulesets.Osu.Edit foreach (var point in slider.Path.ControlPoints) { - oldControlPoints.Enqueue(point.Position.Value); - point.Position.Value *= pathRelativeDeltaScale; + oldControlPoints.Enqueue(point.Position); + point.Position *= pathRelativeDeltaScale; } // Maintain the path types in case they were defaulted to bezier at some point during scaling for (int i = 0; i < slider.Path.ControlPoints.Count; ++i) - slider.Path.ControlPoints[i].Type.Value = referencePathTypes[i]; + slider.Path.ControlPoints[i].Type = referencePathTypes[i]; //if sliderhead or sliderend end up outside playfield, revert scaling. Quad scaledQuad = getSurroundingQuad(new OsuHitObject[] { slider }); @@ -194,7 +194,7 @@ namespace osu.Game.Rulesets.Osu.Edit return; foreach (var point in slider.Path.ControlPoints) - point.Position.Value = oldControlPoints.Dequeue(); + point.Position = oldControlPoints.Dequeue(); } private void scaleHitObjects(OsuHitObject[] hitObjects, Anchor reference, Vector2 scale) diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index 8ba9597dc3..c4420b1e87 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Osu.Objects if (value != null) { - path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position.Value, c.Type.Value))); + path.ControlPoints.AddRange(value.ControlPoints.Select(c => new PathControlPoint(c.Position, c.Type))); path.ExpectedDistance.Value = value.ExpectedDistance.Value; } } diff --git a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs index 57ec51cf64..bfd6ac3ad3 100644 --- a/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs +++ b/osu.Game.Rulesets.Osu/Utils/OsuHitObjectGenerationUtils.cs @@ -119,9 +119,9 @@ namespace osu.Game.Rulesets.Osu.Utils slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(OsuPlayfield.BASE_SIZE.X - h.Position.X, h.Position.Y)); - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); foreach (var point in controlPoints) - point.Position.Value = new Vector2(-point.Position.Value.X, point.Position.Value.Y); + point.Position = new Vector2(-point.Position.X, point.Position.Y); slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); } @@ -140,9 +140,9 @@ namespace osu.Game.Rulesets.Osu.Utils slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); slider.NestedHitObjects.OfType().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y)); - var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position.Value, p.Type.Value)).ToArray(); + var controlPoints = slider.Path.ControlPoints.Select(p => new PathControlPoint(p.Position, p.Type)).ToArray(); foreach (var point in controlPoints) - point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y); + point.Position = new Vector2(point.Position.X, -point.Position.Y); slider.Path = new SliderPath(controlPoints, slider.Path.ExpectedDistance.Value); } diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index dd4c24698c..12633ee8c9 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -666,111 +666,111 @@ namespace osu.Game.Tests.Beatmaps.Formats // Multi-segment var first = ((IHasPath)decoded.HitObjects[0]).Path; - Assert.That(first.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(first.ControlPoints[0].Type.Value, Is.EqualTo(PathType.PerfectCurve)); - Assert.That(first.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(161, -244))); - Assert.That(first.ControlPoints[1].Type.Value, Is.EqualTo(null)); + Assert.That(first.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(first.ControlPoints[0].Type, Is.EqualTo(PathType.PerfectCurve)); + Assert.That(first.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244))); + Assert.That(first.ControlPoints[1].Type, Is.EqualTo(null)); - Assert.That(first.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(376, -3))); - Assert.That(first.ControlPoints[2].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(first.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(68, 15))); - Assert.That(first.ControlPoints[3].Type.Value, Is.EqualTo(null)); - Assert.That(first.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(259, -132))); - Assert.That(first.ControlPoints[4].Type.Value, Is.EqualTo(null)); - Assert.That(first.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(92, -107))); - Assert.That(first.ControlPoints[5].Type.Value, Is.EqualTo(null)); + Assert.That(first.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3))); + Assert.That(first.ControlPoints[2].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(first.ControlPoints[3].Position, Is.EqualTo(new Vector2(68, 15))); + Assert.That(first.ControlPoints[3].Type, Is.EqualTo(null)); + Assert.That(first.ControlPoints[4].Position, Is.EqualTo(new Vector2(259, -132))); + Assert.That(first.ControlPoints[4].Type, Is.EqualTo(null)); + Assert.That(first.ControlPoints[5].Position, Is.EqualTo(new Vector2(92, -107))); + Assert.That(first.ControlPoints[5].Type, Is.EqualTo(null)); // Single-segment var second = ((IHasPath)decoded.HitObjects[1]).Path; - Assert.That(second.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(second.ControlPoints[0].Type.Value, Is.EqualTo(PathType.PerfectCurve)); - Assert.That(second.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(161, -244))); - Assert.That(second.ControlPoints[1].Type.Value, Is.EqualTo(null)); - Assert.That(second.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(376, -3))); - Assert.That(second.ControlPoints[2].Type.Value, Is.EqualTo(null)); + Assert.That(second.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(second.ControlPoints[0].Type, Is.EqualTo(PathType.PerfectCurve)); + Assert.That(second.ControlPoints[1].Position, Is.EqualTo(new Vector2(161, -244))); + Assert.That(second.ControlPoints[1].Type, Is.EqualTo(null)); + Assert.That(second.ControlPoints[2].Position, Is.EqualTo(new Vector2(376, -3))); + Assert.That(second.ControlPoints[2].Type, Is.EqualTo(null)); // Implicit multi-segment var third = ((IHasPath)decoded.HitObjects[2]).Path; - Assert.That(third.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(third.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(third.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(0, 192))); - Assert.That(third.ControlPoints[1].Type.Value, Is.EqualTo(null)); - Assert.That(third.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(224, 192))); - Assert.That(third.ControlPoints[2].Type.Value, Is.EqualTo(null)); + Assert.That(third.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(third.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(third.ControlPoints[1].Position, Is.EqualTo(new Vector2(0, 192))); + Assert.That(third.ControlPoints[1].Type, Is.EqualTo(null)); + Assert.That(third.ControlPoints[2].Position, Is.EqualTo(new Vector2(224, 192))); + Assert.That(third.ControlPoints[2].Type, Is.EqualTo(null)); - Assert.That(third.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(224, 0))); - Assert.That(third.ControlPoints[3].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(third.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(224, -192))); - Assert.That(third.ControlPoints[4].Type.Value, Is.EqualTo(null)); - Assert.That(third.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(480, -192))); - Assert.That(third.ControlPoints[5].Type.Value, Is.EqualTo(null)); - Assert.That(third.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(480, 0))); - Assert.That(third.ControlPoints[6].Type.Value, Is.EqualTo(null)); + Assert.That(third.ControlPoints[3].Position, Is.EqualTo(new Vector2(224, 0))); + Assert.That(third.ControlPoints[3].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(third.ControlPoints[4].Position, Is.EqualTo(new Vector2(224, -192))); + Assert.That(third.ControlPoints[4].Type, Is.EqualTo(null)); + Assert.That(third.ControlPoints[5].Position, Is.EqualTo(new Vector2(480, -192))); + Assert.That(third.ControlPoints[5].Type, Is.EqualTo(null)); + Assert.That(third.ControlPoints[6].Position, Is.EqualTo(new Vector2(480, 0))); + Assert.That(third.ControlPoints[6].Type, Is.EqualTo(null)); // Last control point duplicated var fourth = ((IHasPath)decoded.HitObjects[3]).Path; - Assert.That(fourth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(fourth.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(fourth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(1, 1))); - Assert.That(fourth.ControlPoints[1].Type.Value, Is.EqualTo(null)); - Assert.That(fourth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(2, 2))); - Assert.That(fourth.ControlPoints[2].Type.Value, Is.EqualTo(null)); - Assert.That(fourth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(3, 3))); - Assert.That(fourth.ControlPoints[3].Type.Value, Is.EqualTo(null)); - Assert.That(fourth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(3, 3))); - Assert.That(fourth.ControlPoints[4].Type.Value, Is.EqualTo(null)); + Assert.That(fourth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(fourth.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(fourth.ControlPoints[1].Position, Is.EqualTo(new Vector2(1, 1))); + Assert.That(fourth.ControlPoints[1].Type, Is.EqualTo(null)); + Assert.That(fourth.ControlPoints[2].Position, Is.EqualTo(new Vector2(2, 2))); + Assert.That(fourth.ControlPoints[2].Type, Is.EqualTo(null)); + Assert.That(fourth.ControlPoints[3].Position, Is.EqualTo(new Vector2(3, 3))); + Assert.That(fourth.ControlPoints[3].Type, Is.EqualTo(null)); + Assert.That(fourth.ControlPoints[4].Position, Is.EqualTo(new Vector2(3, 3))); + Assert.That(fourth.ControlPoints[4].Type, Is.EqualTo(null)); // Last control point in segment duplicated var fifth = ((IHasPath)decoded.HitObjects[4]).Path; - Assert.That(fifth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(fifth.ControlPoints[0].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(fifth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(1, 1))); - Assert.That(fifth.ControlPoints[1].Type.Value, Is.EqualTo(null)); - Assert.That(fifth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(2, 2))); - Assert.That(fifth.ControlPoints[2].Type.Value, Is.EqualTo(null)); - Assert.That(fifth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(3, 3))); - Assert.That(fifth.ControlPoints[3].Type.Value, Is.EqualTo(null)); - Assert.That(fifth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(3, 3))); - Assert.That(fifth.ControlPoints[4].Type.Value, Is.EqualTo(null)); + Assert.That(fifth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(fifth.ControlPoints[0].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(fifth.ControlPoints[1].Position, Is.EqualTo(new Vector2(1, 1))); + Assert.That(fifth.ControlPoints[1].Type, Is.EqualTo(null)); + Assert.That(fifth.ControlPoints[2].Position, Is.EqualTo(new Vector2(2, 2))); + Assert.That(fifth.ControlPoints[2].Type, Is.EqualTo(null)); + Assert.That(fifth.ControlPoints[3].Position, Is.EqualTo(new Vector2(3, 3))); + Assert.That(fifth.ControlPoints[3].Type, Is.EqualTo(null)); + Assert.That(fifth.ControlPoints[4].Position, Is.EqualTo(new Vector2(3, 3))); + Assert.That(fifth.ControlPoints[4].Type, Is.EqualTo(null)); - Assert.That(fifth.ControlPoints[5].Position.Value, Is.EqualTo(new Vector2(4, 4))); - Assert.That(fifth.ControlPoints[5].Type.Value, Is.EqualTo(PathType.Bezier)); - Assert.That(fifth.ControlPoints[6].Position.Value, Is.EqualTo(new Vector2(5, 5))); - Assert.That(fifth.ControlPoints[6].Type.Value, Is.EqualTo(null)); + Assert.That(fifth.ControlPoints[5].Position, Is.EqualTo(new Vector2(4, 4))); + Assert.That(fifth.ControlPoints[5].Type, Is.EqualTo(PathType.Bezier)); + Assert.That(fifth.ControlPoints[6].Position, Is.EqualTo(new Vector2(5, 5))); + Assert.That(fifth.ControlPoints[6].Type, Is.EqualTo(null)); // Implicit perfect-curve multi-segment(Should convert to bezier to match stable) var sixth = ((IHasPath)decoded.HitObjects[5]).Path; - Assert.That(sixth.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(sixth.ControlPoints[0].Type.Value == PathType.Bezier); - Assert.That(sixth.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145))); - Assert.That(sixth.ControlPoints[1].Type.Value == null); - Assert.That(sixth.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75))); + Assert.That(sixth.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(sixth.ControlPoints[0].Type == PathType.Bezier); + Assert.That(sixth.ControlPoints[1].Position, Is.EqualTo(new Vector2(75, 145))); + Assert.That(sixth.ControlPoints[1].Type == null); + Assert.That(sixth.ControlPoints[2].Position, Is.EqualTo(new Vector2(170, 75))); - Assert.That(sixth.ControlPoints[2].Type.Value == PathType.Bezier); - Assert.That(sixth.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145))); - Assert.That(sixth.ControlPoints[3].Type.Value == null); - Assert.That(sixth.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20))); - Assert.That(sixth.ControlPoints[4].Type.Value == null); + Assert.That(sixth.ControlPoints[2].Type == PathType.Bezier); + Assert.That(sixth.ControlPoints[3].Position, Is.EqualTo(new Vector2(300, 145))); + Assert.That(sixth.ControlPoints[3].Type == null); + Assert.That(sixth.ControlPoints[4].Position, Is.EqualTo(new Vector2(410, 20))); + Assert.That(sixth.ControlPoints[4].Type == null); // Explicit perfect-curve multi-segment(Should not convert to bezier) var seventh = ((IHasPath)decoded.HitObjects[6]).Path; - Assert.That(seventh.ControlPoints[0].Position.Value, Is.EqualTo(Vector2.Zero)); - Assert.That(seventh.ControlPoints[0].Type.Value == PathType.PerfectCurve); - Assert.That(seventh.ControlPoints[1].Position.Value, Is.EqualTo(new Vector2(75, 145))); - Assert.That(seventh.ControlPoints[1].Type.Value == null); - Assert.That(seventh.ControlPoints[2].Position.Value, Is.EqualTo(new Vector2(170, 75))); + Assert.That(seventh.ControlPoints[0].Position, Is.EqualTo(Vector2.Zero)); + Assert.That(seventh.ControlPoints[0].Type == PathType.PerfectCurve); + Assert.That(seventh.ControlPoints[1].Position, Is.EqualTo(new Vector2(75, 145))); + Assert.That(seventh.ControlPoints[1].Type == null); + Assert.That(seventh.ControlPoints[2].Position, Is.EqualTo(new Vector2(170, 75))); - Assert.That(seventh.ControlPoints[2].Type.Value == PathType.PerfectCurve); - Assert.That(seventh.ControlPoints[3].Position.Value, Is.EqualTo(new Vector2(300, 145))); - Assert.That(seventh.ControlPoints[3].Type.Value == null); - Assert.That(seventh.ControlPoints[4].Position.Value, Is.EqualTo(new Vector2(410, 20))); - Assert.That(seventh.ControlPoints[4].Type.Value == null); + Assert.That(seventh.ControlPoints[2].Type == PathType.PerfectCurve); + Assert.That(seventh.ControlPoints[3].Position, Is.EqualTo(new Vector2(300, 145))); + Assert.That(seventh.ControlPoints[3].Type == null); + Assert.That(seventh.ControlPoints[4].Position, Is.EqualTo(new Vector2(410, 20))); + Assert.That(seventh.ControlPoints[4].Type == null); } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs index 606395c289..9750838433 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSliderPath.cs @@ -74,14 +74,14 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestAddControlPoint() { AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100)))); - AddStep("add point", () => path.ControlPoints.Add(new PathControlPoint { Position = { Value = new Vector2(100) } })); + AddStep("add point", () => path.ControlPoints.Add(new PathControlPoint { Position = new Vector2(100) })); } [Test] public void TestInsertControlPoint() { AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(100)))); - AddStep("insert point", () => path.ControlPoints.Insert(1, new PathControlPoint { Position = { Value = new Vector2(0, 100) } })); + AddStep("insert point", () => path.ControlPoints.Insert(1, new PathControlPoint { Position = new Vector2(0, 100) })); } [Test] @@ -95,14 +95,14 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestChangePathType() { AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100)))); - AddStep("change type to bezier", () => path.ControlPoints[0].Type.Value = PathType.Bezier); + AddStep("change type to bezier", () => path.ControlPoints[0].Type = PathType.Bezier); } [Test] public void TestAddSegmentByChangingType() { AddStep("create path", () => path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0)))); - AddStep("change second point type to bezier", () => path.ControlPoints[1].Type.Value = PathType.Bezier); + AddStep("change second point type to bezier", () => path.ControlPoints[1].Type = PathType.Bezier); } [Test] @@ -111,10 +111,10 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("create path", () => { path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0))); - path.ControlPoints[1].Type.Value = PathType.Bezier; + path.ControlPoints[1].Type = PathType.Bezier; }); - AddStep("change second point type to null", () => path.ControlPoints[1].Type.Value = null); + AddStep("change second point type to null", () => path.ControlPoints[1].Type = null); } [Test] @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.Gameplay AddStep("create path", () => { path.ControlPoints.AddRange(createSegment(PathType.Linear, Vector2.Zero, new Vector2(0, 100), new Vector2(100), new Vector2(100, 0))); - path.ControlPoints[1].Type.Value = PathType.Bezier; + path.ControlPoints[1].Type = PathType.Bezier; }); AddStep("remove second point", () => path.ControlPoints.RemoveAt(1)); @@ -185,8 +185,8 @@ namespace osu.Game.Tests.Visual.Gameplay private List createSegment(PathType type, params Vector2[] controlPoints) { - var points = controlPoints.Select(p => new PathControlPoint { Position = { Value = p } }).ToList(); - points[0].Type.Value = type; + var points = controlPoints.Select(p => new PathControlPoint { Position = p }).ToList(); + points[0].Type = type; return points; } } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index fade7183a3..246dc991d5 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -323,22 +323,22 @@ namespace osu.Game.Beatmaps.Formats { PathControlPoint point = pathData.Path.ControlPoints[i]; - if (point.Type.Value != null) + if (point.Type != null) { // We've reached a new (explicit) segment! // Explicit segments have a new format in which the type is injected into the middle of the control point string. // To preserve compatibility with osu-stable as much as possible, explicit segments with the same type are converted to use implicit segments by duplicating the control point. // One exception are consecutive perfect curves, which aren't supported in osu!stable and can lead to decoding issues if encoded as implicit segments - bool needsExplicitSegment = point.Type.Value != lastType || point.Type.Value == PathType.PerfectCurve; + bool needsExplicitSegment = point.Type != lastType || point.Type == PathType.PerfectCurve; // Another exception to this is when the last two control points of the last segment were duplicated. This is not a scenario supported by osu!stable. // Lazer does not add implicit segments for the last two control points of _any_ explicit segment, so an explicit segment is forced in order to maintain consistency with the decoder. if (i > 1) { // We need to use the absolute control point position to determine equality, otherwise floating point issues may arise. - Vector2 p1 = position + pathData.Path.ControlPoints[i - 1].Position.Value; - Vector2 p2 = position + pathData.Path.ControlPoints[i - 2].Position.Value; + Vector2 p1 = position + pathData.Path.ControlPoints[i - 1].Position; + Vector2 p2 = position + pathData.Path.ControlPoints[i - 2].Position; if ((int)p1.X == (int)p2.X && (int)p1.Y == (int)p2.Y) needsExplicitSegment = true; @@ -346,7 +346,7 @@ namespace osu.Game.Beatmaps.Formats if (needsExplicitSegment) { - switch (point.Type.Value) + switch (point.Type) { case PathType.Bezier: writer.Write("B|"); @@ -365,18 +365,18 @@ namespace osu.Game.Beatmaps.Formats break; } - lastType = point.Type.Value; + lastType = point.Type; } else { // New segment with the same type - duplicate the control point - writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}|")); + writer.Write(FormattableString.Invariant($"{position.X + point.Position.X}:{position.Y + point.Position.Y}|")); } } if (i != 0) { - writer.Write(FormattableString.Invariant($"{position.X + point.Position.Value.X}:{position.Y + point.Position.Value.Y}")); + writer.Write(FormattableString.Invariant($"{position.X + point.Position.X}:{position.Y + point.Position.Y}")); writer.Write(i != pathData.Path.ControlPoints.Count - 1 ? "|" : ","); } } diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index e8a5463cce..0942a7264d 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -323,7 +323,7 @@ namespace osu.Game.Rulesets.Objects.Legacy } // The first control point must have a definite type. - vertices[0].Type.Value = type; + vertices[0].Type = type; // A path can have multiple implicit segments of the same type if there are two sequential control points with the same position. // To handle such cases, this code may return multiple path segments with the final control point in each segment having a non-null type. @@ -337,7 +337,7 @@ namespace osu.Game.Rulesets.Objects.Legacy while (++endIndex < vertices.Length - endPointLength) { // Keep incrementing while an implicit segment doesn't need to be started - if (vertices[endIndex].Position.Value != vertices[endIndex - 1].Position.Value) + if (vertices[endIndex].Position != vertices[endIndex - 1].Position) continue; // The last control point of each segment is not allowed to start a new implicit segment. @@ -345,7 +345,7 @@ namespace osu.Game.Rulesets.Objects.Legacy continue; // Force a type on the last point, and return the current control point set as a segment. - vertices[endIndex - 1].Type.Value = type; + vertices[endIndex - 1].Type = type; yield return vertices.AsMemory().Slice(startIndex, endIndex - startIndex); // Skip the current control point - as it's the same as the one that's just been returned. @@ -360,11 +360,11 @@ namespace osu.Game.Rulesets.Objects.Legacy string[] vertexSplit = value.Split(':'); Vector2 pos = new Vector2((int)Parsing.ParseDouble(vertexSplit[0], Parsing.MAX_COORDINATE_VALUE), (int)Parsing.ParseDouble(vertexSplit[1], Parsing.MAX_COORDINATE_VALUE)) - startPos; - point = new PathControlPoint { Position = { Value = pos } }; + point = new PathControlPoint { Position = pos }; } - static bool isLinear(PathControlPoint[] p) => Precision.AlmostEquals(0, (p[1].Position.Value.Y - p[0].Position.Value.Y) * (p[2].Position.Value.X - p[0].Position.Value.X) - - (p[1].Position.Value.X - p[0].Position.Value.X) * (p[2].Position.Value.Y - p[0].Position.Value.Y)); + static bool isLinear(PathControlPoint[] p) => Precision.AlmostEquals(0, (p[1].Position.Y - p[0].Position.Y) * (p[2].Position.X - p[0].Position.X) + - (p[1].Position.X - p[0].Position.X) * (p[2].Position.Y - p[0].Position.Y)); } private PathControlPoint[] mergePointsLists(List> controlPointList) diff --git a/osu.Game/Rulesets/Objects/PathControlPoint.cs b/osu.Game/Rulesets/Objects/PathControlPoint.cs index f11917f4f4..53eb430fa3 100644 --- a/osu.Game/Rulesets/Objects/PathControlPoint.cs +++ b/osu.Game/Rulesets/Objects/PathControlPoint.cs @@ -3,7 +3,6 @@ using System; using Newtonsoft.Json; -using osu.Framework.Bindables; using osu.Game.Rulesets.Objects.Types; using osuTK; @@ -11,31 +10,55 @@ namespace osu.Game.Rulesets.Objects { public class PathControlPoint : IEquatable { + private Vector2 position; + /// /// The position of this . /// [JsonProperty] - public readonly Bindable Position = new Bindable(); + public Vector2 Position + { + get => position; + set + { + if (value == position) + return; + + position = value; + Changed?.Invoke(); + } + } + + private PathType? type; /// /// The type of path segment starting at this . /// If null, this will be a part of the previous path segment. /// [JsonProperty] - public readonly Bindable Type = new Bindable(); + public PathType? Type + { + get => type; + set + { + if (value == type) + return; + + type = value; + Changed?.Invoke(); + } + } /// /// Invoked when any property of this is changed. /// - internal event Action Changed; + public event Action Changed; /// /// Creates a new . /// public PathControlPoint() { - Position.ValueChanged += _ => Changed?.Invoke(); - Type.ValueChanged += _ => Changed?.Invoke(); } /// @@ -46,10 +69,10 @@ namespace osu.Game.Rulesets.Objects public PathControlPoint(Vector2 position, PathType? type = null) : this() { - Position.Value = position; - Type.Value = type; + Position = position; + Type = type; } - public bool Equals(PathControlPoint other) => Position.Value == other?.Position.Value && Type.Value == other.Type.Value; + public bool Equals(PathControlPoint other) => Position == other?.Position && Type == other.Type; } } diff --git a/osu.Game/Rulesets/Objects/SliderPath.cs b/osu.Game/Rulesets/Objects/SliderPath.cs index 55ef0bc5f6..9cc215589b 100644 --- a/osu.Game/Rulesets/Objects/SliderPath.cs +++ b/osu.Game/Rulesets/Objects/SliderPath.cs @@ -169,7 +169,7 @@ namespace osu.Game.Rulesets.Objects foreach (PathControlPoint point in ControlPoints) { - if (point.Type.Value != null) + if (point.Type != null) { if (!found) pointsInCurrentSegment.Clear(); @@ -215,18 +215,18 @@ namespace osu.Game.Rulesets.Objects Vector2[] vertices = new Vector2[ControlPoints.Count]; for (int i = 0; i < ControlPoints.Count; i++) - vertices[i] = ControlPoints[i].Position.Value; + vertices[i] = ControlPoints[i].Position; int start = 0; for (int i = 0; i < ControlPoints.Count; i++) { - if (ControlPoints[i].Type.Value == null && i < ControlPoints.Count - 1) + if (ControlPoints[i].Type == null && i < ControlPoints.Count - 1) continue; // The current vertex ends the segment var segmentVertices = vertices.AsSpan().Slice(start, i - start + 1); - var segmentType = ControlPoints[start].Type.Value ?? PathType.Linear; + var segmentType = ControlPoints[start].Type ?? PathType.Linear; foreach (Vector2 t in calculateSubPath(segmentVertices, segmentType)) { diff --git a/osu.Game/Rulesets/Objects/SliderPathExtensions.cs b/osu.Game/Rulesets/Objects/SliderPathExtensions.cs index 1438c2f128..663746bfca 100644 --- a/osu.Game/Rulesets/Objects/SliderPathExtensions.cs +++ b/osu.Game/Rulesets/Objects/SliderPathExtensions.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Objects public static void Reverse(this SliderPath sliderPath, out Vector2 positionalOffset) { var points = sliderPath.ControlPoints.ToArray(); - positionalOffset = points.Last().Position.Value; + positionalOffset = points.Last().Position; sliderPath.ControlPoints.Clear(); @@ -28,17 +28,13 @@ namespace osu.Game.Rulesets.Objects for (var i = 0; i < points.Length; i++) { var p = points[i]; - p.Position.Value -= positionalOffset; + p.Position -= positionalOffset; // propagate types forwards to last null type if (i == points.Length - 1) - p.Type.Value = lastType; - else if (p.Type.Value != null) - { - var newType = p.Type.Value; - p.Type.Value = lastType; - lastType = newType; - } + p.Type = lastType; + else if (p.Type != null) + (p.Type, lastType) = (lastType, p.Type); sliderPath.ControlPoints.Insert(0, p); } From 69064c1938e6f574ca8908939fc144aeb35cafae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 03:41:58 +0900 Subject: [PATCH 636/961] Avoid unnecessary unbind operations when constructing `FollowPointLifetimeEntry` --- .../Connections/FollowPointLifetimeEntry.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs index 82bca0a4e2..c0d3572adf 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Diagnostics; using osu.Framework.Bindables; using osu.Framework.Graphics.Performance; using osu.Game.Rulesets.Objects; @@ -20,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections { Start = start; LifetimeStart = Start.StartTime; - - bindEvents(); } private OsuHitObject? end; @@ -41,31 +40,39 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections } } + private bool wasBound = false; + private void bindEvents() { UnbindEvents(); + if (End == null) + return; + // Note: Positions are bound for instantaneous feedback from positional changes from the editor, before ApplyDefaults() is called on hitobjects. Start.DefaultsApplied += onDefaultsApplied; Start.PositionBindable.ValueChanged += onPositionChanged; - if (End != null) - { - End.DefaultsApplied += onDefaultsApplied; - End.PositionBindable.ValueChanged += onPositionChanged; - } + End.DefaultsApplied += onDefaultsApplied; + End.PositionBindable.ValueChanged += onPositionChanged; + + wasBound = true; } public void UnbindEvents() { + if (!wasBound) + return; + + Debug.Assert(End != null); + Start.DefaultsApplied -= onDefaultsApplied; Start.PositionBindable.ValueChanged -= onPositionChanged; - if (End != null) - { - End.DefaultsApplied -= onDefaultsApplied; - End.PositionBindable.ValueChanged -= onPositionChanged; - } + End.DefaultsApplied -= onDefaultsApplied; + End.PositionBindable.ValueChanged -= onPositionChanged; + + wasBound = false; } private void onDefaultsApplied(HitObject obj) => refreshLifetimes(); From f4199958d93995b0db1235fc986e1f07d1ef80ec Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 04:01:37 +0900 Subject: [PATCH 637/961] Avoid unnecessary array/LINQ operations when replay frames have no action changes --- osu.Game/Input/Handlers/ReplayInputHandler.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/osu.Game/Input/Handlers/ReplayInputHandler.cs b/osu.Game/Input/Handlers/ReplayInputHandler.cs index cd76000f98..e4aec4edac 100644 --- a/osu.Game/Input/Handlers/ReplayInputHandler.cs +++ b/osu.Game/Input/Handlers/ReplayInputHandler.cs @@ -42,9 +42,24 @@ namespace osu.Game.Input.Handlers if (!(state is RulesetInputManagerInputState inputState)) throw new InvalidOperationException($"{nameof(ReplayState)} should only be applied to a {nameof(RulesetInputManagerInputState)}"); - var lastPressed = inputState.LastReplayState?.PressedActions ?? new List(); - var released = lastPressed.Except(PressedActions).ToArray(); - var pressed = PressedActions.Except(lastPressed).ToArray(); + T[] released = Array.Empty(); + T[] pressed = Array.Empty(); + + var lastPressed = inputState.LastReplayState?.PressedActions; + + if (lastPressed == null || lastPressed.Count == 0) + { + pressed = PressedActions.ToArray(); + } + else if (PressedActions.Count == 0) + { + released = lastPressed.ToArray(); + } + else if (!lastPressed.SequenceEqual(PressedActions)) + { + released = lastPressed.Except(PressedActions).ToArray(); + pressed = PressedActions.Except(lastPressed).ToArray(); + } inputState.LastReplayState = this; From 8cfb3d456b3014612c835037f83ce06d3130a296 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 04:12:23 +0900 Subject: [PATCH 638/961] Avoid expensive text spacing transforms for now --- osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index 79655c33e4..b23087a1f3 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -77,7 +77,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables base.PlayAnimation(); if (Result != HitResult.Miss) - JudgementText.TransformSpacingTo(Vector2.Zero).Then().TransformSpacingTo(new Vector2(14, 0), 1800, Easing.OutQuint); + JudgementText.ScaleTo(new Vector2(0.8f, 1)).Then().ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint); } } } From e32933eb54f5df45e18367387a53c9d32401601f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 04:19:49 +0900 Subject: [PATCH 639/961] Avoid `Enum.GetValues` in each score population pass --- osu.Game/Rulesets/Scoring/HitResult.cs | 7 +++++++ osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/HitResult.cs b/osu.Game/Rulesets/Scoring/HitResult.cs index eaa1f95744..5599ed96a3 100644 --- a/osu.Game/Rulesets/Scoring/HitResult.cs +++ b/osu.Game/Rulesets/Scoring/HitResult.cs @@ -1,8 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.ComponentModel; using System.Diagnostics; +using System.Linq; using osu.Framework.Utils; namespace osu.Game.Rulesets.Scoring @@ -171,6 +173,11 @@ namespace osu.Game.Rulesets.Scoring /// public static bool IsScorable(this HitResult result) => result >= HitResult.Miss && result < HitResult.IgnoreMiss; + /// + /// An array of all scorable s. + /// + public static readonly HitResult[] SCORABLE_TYPES = ((HitResult[])Enum.GetValues(typeof(HitResult))).Where(r => r.IsScorable()).ToArray(); + /// /// Whether a is valid within a given range. /// diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 6a2601170c..16f2607bad 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -339,7 +339,7 @@ namespace osu.Game.Rulesets.Scoring score.Accuracy = Accuracy.Value; score.Rank = Rank.Value; - foreach (var result in Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.IsScorable())) + foreach (var result in HitResultExtensions.SCORABLE_TYPES) score.Statistics[result] = GetStatistic(result); score.HitEvents = hitEvents; From e15198f0771836d44ecf7046f8da5ea3d4cb98fe Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 13:47:10 +0900 Subject: [PATCH 640/961] Update missed tests --- .../Editor/TestScenePathControlPointVisualiser.cs | 2 +- .../Editor/TestSceneSliderControlPointPiece.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs index 53a9f06eee..5a1aa42ed1 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestScenePathControlPointVisualiser.cs @@ -166,7 +166,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { AddStep($"move mouse to control point {index}", () => { - Vector2 position = slider.Path.ControlPoints[index].Position.Value; + Vector2 position = slider.Path.ControlPoints[index].Position; InputManager.MoveMouseTo(visualiser.Pieces[0].Parent.ToScreenSpace(position)); }); } diff --git a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs index 24b947c854..6bfe7f892b 100644 --- a/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs +++ b/osu.Game.Rulesets.Osu.Tests/Editor/TestSceneSliderControlPointPiece.cs @@ -108,9 +108,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor [Test] public void TestDragControlPointPathAfterChangingType() { - AddStep("change type to bezier", () => slider.Path.ControlPoints[2].Type.Value = PathType.Bezier); + AddStep("change type to bezier", () => slider.Path.ControlPoints[2].Type = PathType.Bezier); AddStep("add point", () => slider.Path.ControlPoints.Add(new PathControlPoint(new Vector2(500, 10)))); - AddStep("change type to perfect", () => slider.Path.ControlPoints[3].Type.Value = PathType.PerfectCurve); + AddStep("change type to perfect", () => slider.Path.ControlPoints[3].Type = PathType.PerfectCurve); moveMouseToControlPoint(4); AddStep("hold", () => InputManager.PressButton(MouseButton.Left)); @@ -137,15 +137,15 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor { AddStep($"move mouse to control point {index}", () => { - Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position.Value; + Vector2 position = slider.Position + slider.Path.ControlPoints[index].Position; InputManager.MoveMouseTo(drawableObject.Parent.ToScreenSpace(position)); }); } - private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => slider.Path.ControlPoints[index].Type.Value == type); + private void assertControlPointType(int index, PathType type) => AddAssert($"control point {index} is {type}", () => slider.Path.ControlPoints[index].Type == type); private void assertControlPointPosition(int index, Vector2 position) => - AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, slider.Path.ControlPoints[index].Position.Value, 1)); + AddAssert($"control point {index} at {position}", () => Precision.AlmostEquals(position, slider.Path.ControlPoints[index].Position, 1)); private class TestSliderBlueprint : SliderSelectionBlueprint { From e633b2716d99270bb722521ec71718e43c7600be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 13:58:23 +0900 Subject: [PATCH 641/961] Fix regression in outro skip handling logic --- osu.Game/Screens/Play/SkipOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/SkipOverlay.cs b/osu.Game/Screens/Play/SkipOverlay.cs index 71a70991d2..a2145b7014 100644 --- a/osu.Game/Screens/Play/SkipOverlay.cs +++ b/osu.Game/Screens/Play/SkipOverlay.cs @@ -102,7 +102,7 @@ namespace osu.Game.Screens.Play public override void Show() { base.Show(); - fadeContainer.Show(); + fadeContainer.TriggerShow(); } protected override void LoadComplete() From 17f6efc6fecad7d7d59632f6ca84a7922a0c5059 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 14:02:56 +0900 Subject: [PATCH 642/961] Fix missed cases of incorrect `.Value` usage Changing from `Bindable` to `Nullable` comes with its issues... --- .../Editor/TestSceneJuiceStreamSelectionBlueprint.cs | 4 ++-- .../Sliders/Components/PathControlPointVisualiser.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs index f5ef5c5e18..5e73a89069 100644 --- a/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs +++ b/osu.Game.Rulesets.Catch.Tests/Editor/TestSceneJuiceStreamSelectionBlueprint.cs @@ -210,9 +210,9 @@ namespace osu.Game.Rulesets.Catch.Tests.Editor new Vector2(50, 200), }), 0.5); AddAssert("1 vertex per 1 nested HO", () => getVertices().Count == hitObject.NestedHitObjects.Count); - AddAssert("slider path not yet changed", () => hitObject.Path.ControlPoints[0].Type.Value == PathType.PerfectCurve); + AddAssert("slider path not yet changed", () => hitObject.Path.ControlPoints[0].Type == PathType.PerfectCurve); addAddVertexSteps(150, 150); - AddAssert("slider path change to linear", () => hitObject.Path.ControlPoints[0].Type.Value == PathType.Linear); + AddAssert("slider path change to linear", () => hitObject.Path.ControlPoints[0].Type == PathType.Linear); } private void addBlueprintStep(double time, float x, SliderPath sliderPath, double velocity) => AddStep("add selection blueprint", () => diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs index ac1953c632..6269a41350 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/Components/PathControlPointVisualiser.cs @@ -241,7 +241,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components private MenuItem createMenuItemForPathType(PathType? type) { int totalCount = Pieces.Count(p => p.IsSelected.Value); - int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type.Value == type); + int countOfState = Pieces.Where(p => p.IsSelected.Value).Count(p => p.ControlPoint.Type == type); var item = new TernaryStateRadioMenuItem(type == null ? "Inherit" : type.ToString().Humanize(), MenuItemType.Standard, _ => { From b9ea984c360bebb3d95dac301a9fd01c4ca63900 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 26 Aug 2021 08:18:58 +0300 Subject: [PATCH 643/961] Remove redundant default value --- .../Objects/Drawables/Connections/FollowPointLifetimeEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs index c0d3572adf..30ff6b8984 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Connections/FollowPointLifetimeEntry.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections } } - private bool wasBound = false; + private bool wasBound; private void bindEvents() { From e341f471b01b4b4acc3ce5a51c71e2f6545b0537 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 26 Aug 2021 15:29:22 +0900 Subject: [PATCH 644/961] Add lobby sfx for join/leave/kick/ready/unready events --- .../TestSceneMultiplayerLobbyEvents.cs | 216 ++++++++++++++++++ .../Match/MultiplayerReadyButton.cs | 45 ++-- .../Participants/ParticipantsList.cs | 34 ++- 3 files changed, 278 insertions(+), 17 deletions(-) create mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs new file mode 100644 index 0000000000..accfdceaad --- /dev/null +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs @@ -0,0 +1,216 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Platform; +using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Online.Multiplayer; +using osu.Game.Online.Rooms; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; +using osu.Game.Screens; +using osu.Game.Screens.OnlinePlay.Components; +using osu.Game.Screens.OnlinePlay.Lounge; +using osu.Game.Screens.OnlinePlay.Multiplayer; +using osu.Game.Screens.OnlinePlay.Multiplayer.Match; +using osu.Game.Tests.Resources; +using osu.Game.Users; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Multiplayer +{ + public class TestSceneMultiplayerLobbyEvents : ScreenTestScene + { + private BeatmapManager beatmaps; + private RulesetStore rulesets; + private BeatmapSetInfo importedSet; + + private DependenciesScreen dependenciesScreen; + private TestMultiplayer multiplayerScreen; + private TestMultiplayerClient client; + + private TestRequestHandlingMultiplayerRoomManager roomManager => multiplayerScreen.RoomManager; + + [Cached(typeof(UserLookupCache))] + private UserLookupCache lookupCache = new TestUserLookupCache(); + + [BackgroundDependencyLoader] + private void load(GameHost host, AudioManager audio) + { + Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); + Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); + } + + public override void SetUpSteps() + { + base.SetUpSteps(); + + AddStep("import beatmap", () => + { + beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); + importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); + }); + + AddStep("create multiplayer screen", () => multiplayerScreen = new TestMultiplayer()); + + AddStep("load dependencies", () => + { + client = new TestMultiplayerClient(roomManager); + + // The screen gets suspended so it stops receiving updates. + Child = client; + + LoadScreen(dependenciesScreen = new DependenciesScreen(client)); + }); + + AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded); + + AddStep("load multiplayer", () => LoadScreen(multiplayerScreen)); + AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded); + AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + } + + [Test] + public void TestLobbyEvents() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + } + + private void playerJoin() + { + int randomUser = RNG.Next(200000, 500000); + client.AddUser(new User { Id = randomUser, Username = $"user {randomUser}" }); + } + + private void playerLeave() + { + User lastUser = client.Room?.Users.Last().User; + + if (lastUser == null || lastUser == client.LocalUser?.User) + return; + + client.RemoveUser(lastUser); + } + + private void playerKicked() + { + User lastUser = client.Room?.Users.Last().User; + + if (lastUser == null || lastUser == client.LocalUser?.User) + return; + + client.KickUser(lastUser.Id); + } + + private void playerReady() + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); + } + + private void playerUnready() + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle); + } + + private void randomEvent() + { + int eventToPerform = RNG.Next(1, 6); + + switch (eventToPerform) + { + case 1: + playerJoin(); + break; + + case 2: + playerLeave(); + break; + + case 3: + playerKicked(); + break; + + case 4: + playerReady(); + break; + + case 5: + playerUnready(); + break; + } + } + + private void createRoom(Func room) + { + AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().Open(room())); + + AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); + AddWaitStep("wait for transition", 2); + + AddStep("create room", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().Single()); + InputManager.Click(MouseButton.Left); + }); + + AddUntilStep("wait for join", () => client.Room != null); + + AddRepeatStep("random stuff happens", randomEvent, 30); + + // ensure we have a handful of players so the ready-up sounds good :9 + AddRepeatStep("player joins", playerJoin, 5); + + // all ready + AddRepeatStep("players ready up", () => + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); + }, 40); + } + + /// + /// Used for the sole purpose of adding as a resolvable dependency. + /// + private class DependenciesScreen : OsuScreen + { + [Cached(typeof(MultiplayerClient))] + public readonly TestMultiplayerClient Client; + + public DependenciesScreen(TestMultiplayerClient client) + { + Client = client; + } + } + + private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer + { + public new TestRequestHandlingMultiplayerRoomManager RoomManager { get; private set; } + + protected override RoomManager CreateRoomManager() => RoomManager = new TestRequestHandlingMultiplayerRoomManager(); + } + } +} diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index 2a40a61257..9c818fc070 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -35,7 +35,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private IBindable operationInProgress; - private Sample sampleReadyCount; + private Sample sampleReady; + private Sample sampleReadyAll; + private Sample sampleUnready; + private double unreadyLastPlaybackTime; private readonly ButtonWithTrianglesExposed button; @@ -54,10 +57,14 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleReadyCount = audio.Samples.Get(@"SongSelect/select-difficulty"); - operationInProgress = ongoingOperationTracker.InProgress.GetBoundCopy(); operationInProgress.BindValueChanged(_ => updateState()); + + sampleReady = audio.Samples.Get(@"Multiplayer/player-ready"); + sampleReadyAll = audio.Samples.Get(@"Multiplayer/player-ready-all"); + sampleUnready = audio.Samples.Get(@"Multiplayer/player-unready"); + + unreadyLastPlaybackTime = Time.Current; } protected override void OnRoomUpdated() @@ -107,21 +114,27 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match button.Enabled.Value = enableButton; - if (newCountReady != countReady) - { - countReady = newCountReady; - Scheduler.AddOnce(playSound); - } - } - - private void playSound() - { - if (sampleReadyCount == null) + if (newCountReady == countReady) return; - var channel = sampleReadyCount.GetChannel(); - channel.Frequency.Value = 0.77f + countReady * 0.06f; - channel.Play(); + if (newCountReady > countReady) + { + if (newCountReady == newCountTotal) + sampleReadyAll?.Play(); + else + sampleReady?.Play(); + } + else + { + // debounce sample playback to prevent the mass-unready of game mode changes from deafening players + if (Time.Current - unreadyLastPlaybackTime > 10) + { + sampleUnready?.Play(); + unreadyLastPlaybackTime = Time.Current; + } + } + + countReady = newCountReady; } private void updateButtonColour(bool green) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs index 3759e45f18..2ad64e115e 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/ParticipantsList.cs @@ -3,10 +3,13 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; +using osu.Game.Online.Multiplayer; using osuTK; namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants @@ -15,8 +18,12 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { private FillFlowContainer panels; + private Sample userJoinSample; + private Sample userLeftSample; + private Sample userKickedSample; + [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { InternalChild = new OsuContextMenuContainer { @@ -34,6 +41,31 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants } } }; + + userJoinSample = audio.Samples.Get(@"Multiplayer/player-joined"); + userLeftSample = audio.Samples.Get(@"Multiplayer/player-left"); + userKickedSample = audio.Samples.Get(@"Multiplayer/player-kicked"); + } + + protected override void UserJoined(MultiplayerRoomUser user) + { + base.UserJoined(user); + + userJoinSample?.Play(); + } + + protected override void UserLeft(MultiplayerRoomUser user) + { + base.UserLeft(user); + + userLeftSample?.Play(); + } + + protected override void UserKicked(MultiplayerRoomUser user) + { + base.UserKicked(user); + + userKickedSample?.Play(); } protected override void OnRoomUpdated() From 56baecdde45cbfed4789ff2de11c37bb603afb18 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 26 Aug 2021 15:30:20 +0900 Subject: [PATCH 645/961] Add missing interaction sfx to MatchTypePicker --- osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs index c6f9b0f207..216734e55e 100644 --- a/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs +++ b/osu.Game/Screens/OnlinePlay/Match/Components/MatchTypePicker.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Game.Graphics; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.Rooms; using osu.Game.Screens.OnlinePlay.Components; using osuTK; @@ -75,6 +76,7 @@ namespace osu.Game.Screens.OnlinePlay.Match.Components }, }, }, + new HoverClickSounds(), }; } From 15812520bd6d99105fb71c4b0448fb6bd545cd6f Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 26 Aug 2021 09:44:53 +0300 Subject: [PATCH 646/961] Replace global editor test case with mania compose screen test scene --- .../Editor/TestSceneManiaComposeScreen.cs | 64 +++++++++++++++++++ osu.Game/Tests/Visual/EditorTestScene.cs | 10 --- 2 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs new file mode 100644 index 0000000000..0f520215a1 --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestSceneManiaComposeScreen.cs @@ -0,0 +1,64 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania.Beatmaps; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Compose; +using osu.Game.Skinning; +using osu.Game.Tests.Visual; + +namespace osu.Game.Rulesets.Mania.Tests.Editor +{ + public class TestSceneManiaComposeScreen : EditorClockTestScene + { + [Resolved] + private SkinManager skins { get; set; } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("setup compose screen", () => + { + var editorBeatmap = new EditorBeatmap(new ManiaBeatmap(new StageDefinition { Columns = 4 })) + { + BeatmapInfo = { Ruleset = new ManiaRuleset().RulesetInfo }, + }; + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + + Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(EditorBeatmap), editorBeatmap), + (typeof(IBeatSnapProvider), editorBeatmap), + }, + Child = new ComposeScreen { State = { Value = Visibility.Visible } }, + }; + }); + + AddUntilStep("wait for composer", () => this.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); + } + + [Test] + public void TestDefaultSkin() + { + AddStep("set default skin", () => skins.CurrentSkinInfo.Value = SkinInfo.Default); + } + + [Test] + public void TestLegacySkin() + { + AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.Info); + } + } +} diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 2644daa3a4..a393802309 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -3,7 +3,6 @@ using System.Linq; using JetBrains.Annotations; -using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.IO.Stores; @@ -29,9 +28,6 @@ namespace osu.Game.Tests.Visual protected EditorClock EditorClock { get; private set; } - [Resolved] - private SkinManager skins { get; set; } - /// /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . /// @@ -61,12 +57,6 @@ namespace osu.Game.Tests.Visual AddStep("get clock", () => EditorClock = Editor.ChildrenOfType().Single()); } - [Test] - public void TestLegacySkin() - { - AddStep("set legacy skin", () => skins.CurrentSkinInfo.Value = DefaultLegacySkin.Info); - } - protected virtual void LoadEditor() { LoadScreen(Editor = CreateEditor()); From ec85d7f3567569dbc9da26306b4d11ab843809ba Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 17:15:23 +0900 Subject: [PATCH 647/961] Remove unused helper method --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index b3e1b24d8d..29d8a475ef 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -54,11 +54,6 @@ namespace osu.Game.Rulesets.Objects.Drawables /// public readonly Bindable AccentColour = new Bindable(Color4.Gray); - /// - /// Gets the samples that are played by this object during gameplay. - /// - public ISampleInfo[] GetGameplaySamples() => Samples.Samples; - protected PausableSkinnableSound Samples { get; private set; } public virtual IEnumerable GetSamples() => HitObject.Samples; From 15aa0458bc801e3d3ecf6e3a8cc6d93fa0e1ea1d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 17:15:36 +0900 Subject: [PATCH 648/961] Use `PausableSkinnableSound` instead --- osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs index ac2067a913..c18698f77e 100644 --- a/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs +++ b/osu.Game/Rulesets/UI/GameplaySampleTriggerSource.cs @@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.UI InternalChild = hitSounds = new Container { Name = "concurrent sample pool", - ChildrenEnumerable = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new SkinnableSound()) + ChildrenEnumerable = Enumerable.Range(0, max_concurrent_hitsounds).Select(_ => new PausableSkinnableSound()) }; } From f078a9d2bf942745f6f400a5c996357b27a70e21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 17:17:39 +0900 Subject: [PATCH 649/961] Fix incorrect step type --- .../Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs index 3e0a937ffa..fccc1a377c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplaySampleTriggerSource.cs @@ -80,7 +80,7 @@ namespace osu.Game.Tests.Visual.Gameplay { HitObjectLifetimeEntry nextObjectEntry = null; - AddUntilStep("no alive objects", () => getNextAliveObject() == null); + AddAssert("no alive objects", () => getNextAliveObject() == null); AddAssert("check initially correct object", () => sampleTriggerSource.GetMostValidObject() == beatmap.HitObjects[0]); From 90e81a595d0c2fafae408bc8667043682c8a2587 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 Aug 2021 17:19:46 +0900 Subject: [PATCH 650/961] Move `DrumSampleTriggerSource` into its own class to avoid nested references --- .../Skinning/Legacy/LegacyInputDrum.cs | 2 +- .../UI/DrumSampleTriggerSource.cs | 30 +++++++++++++++++++ osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 20 ------------- 3 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs diff --git a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs index 5a76694913..9d35093591 100644 --- a/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs +++ b/osu.Game.Rulesets.Taiko/Skinning/Legacy/LegacyInputDrum.cs @@ -112,7 +112,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy public readonly Sprite Centre; [Resolved] - private InputDrum.DrumSampleTriggerSource sampleTriggerSource { get; set; } + private DrumSampleTriggerSource sampleTriggerSource { get; set; } public LegacyHalfDrum(bool flipped) { diff --git a/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs new file mode 100644 index 0000000000..3279d128d3 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/UI/DrumSampleTriggerSource.cs @@ -0,0 +1,30 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Audio; +using osu.Game.Rulesets.Taiko.Objects; +using osu.Game.Rulesets.UI; + +namespace osu.Game.Rulesets.Taiko.UI +{ + public class DrumSampleTriggerSource : GameplaySampleTriggerSource + { + public DrumSampleTriggerSource(HitObjectContainer hitObjectContainer) + : base(hitObjectContainer) + { + } + + public void Play(HitType hitType) + { + var hitObject = GetMostValidObject(); + + if (hitObject == null) + return; + + PlaySamples(new ISampleInfo[] { hitObject.SampleControlPoint.GetSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_CLAP : HitSampleInfo.HIT_NORMAL) }); + } + + public override void Play() => throw new InvalidOperationException(@"Use override with HitType parameter instead"); + } +} diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 24e2dddb49..3eafd201b7 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Input.Bindings; -using osu.Game.Audio; using osu.Game.Graphics; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.UI; @@ -201,24 +200,5 @@ namespace osu.Game.Rulesets.Taiko.UI } } - public class DrumSampleTriggerSource : GameplaySampleTriggerSource - { - public DrumSampleTriggerSource(HitObjectContainer hitObjectContainer) - : base(hitObjectContainer) - { - } - - public void Play(HitType hitType) - { - var hitObject = GetMostValidObject(); - - if (hitObject == null) - return; - - PlaySamples(new ISampleInfo[] { hitObject.SampleControlPoint.GetSampleInfo(hitType == HitType.Rim ? HitSampleInfo.HIT_CLAP : HitSampleInfo.HIT_NORMAL) }); - } - - public override void Play() => throw new InvalidOperationException(@"Use override with HitType parameter instead"); - } } } From cea632463e781f59ad307e2f373632998656b41e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 26 Aug 2021 22:30:20 +0300 Subject: [PATCH 651/961] Remove empty newline --- osu.Game.Rulesets.Taiko/UI/InputDrum.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs index 3eafd201b7..ddfaf64549 100644 --- a/osu.Game.Rulesets.Taiko/UI/InputDrum.cs +++ b/osu.Game.Rulesets.Taiko/UI/InputDrum.cs @@ -199,6 +199,5 @@ namespace osu.Game.Rulesets.Taiko.UI { } } - } } From 7d9bae450780cab1a51023cd2763a110f0e5eff5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 18:29:49 +0900 Subject: [PATCH 652/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index cae8a946a3..f68d7124a9 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index bac99a098d..8e39c5a3df 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index f3ecc90bea..0e3e87f3c1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 34d185d846f47140ca18e220f3de92fd7623ddeb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 18:39:36 +0900 Subject: [PATCH 653/961] Convert final step to until step to avoid unnecessary delays --- .../Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs index accfdceaad..57ec0843b5 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs @@ -184,12 +184,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddRepeatStep("player joins", playerJoin, 5); // all ready - AddRepeatStep("players ready up", () => + AddUntilStep("all players ready", () => { var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); if (nextUnready != null) client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); - }, 40); + + return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true; + }); } /// From 23414b0c634534ed4b430b024c2e4010d9096aed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 18:44:44 +0900 Subject: [PATCH 654/961] Combine test scene to avoid huge copy paste --- .../Multiplayer/TestSceneMultiplayer.cs | 101 ++++++++ .../TestSceneMultiplayerLobbyEvents.cs | 218 ------------------ 2 files changed, 101 insertions(+), 218 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 7a3507d944..d84fe4b6fb 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -12,6 +12,7 @@ using osu.Framework.Input; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Database; using osu.Game.Graphics.UserInterface; @@ -94,6 +95,106 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("empty step", () => { }); } + [Test] + public void TestLobbyEvents() + { + createRoom(() => new Room + { + Name = { Value = "Test Room" }, + Playlist = + { + new PlaylistItem + { + Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, + Ruleset = { Value = new OsuRuleset().RulesetInfo }, + } + } + }); + + AddRepeatStep("random stuff happens", performRandomAction, 30); + + // ensure we have a handful of players so the ready-up sounds good :9 + AddRepeatStep("player joins", addRandomPlayer, 5); + + // all ready + AddUntilStep("all players ready", () => + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); + + return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true; + }); + } + + private void addRandomPlayer() + { + int randomUser = RNG.Next(200000, 500000); + client.AddUser(new User { Id = randomUser, Username = $"user {randomUser}" }); + } + + private void removeLastUser() + { + User lastUser = client.Room?.Users.Last().User; + + if (lastUser == null || lastUser == client.LocalUser?.User) + return; + + client.RemoveUser(lastUser); + } + + private void kickLastUser() + { + User lastUser = client.Room?.Users.Last().User; + + if (lastUser == null || lastUser == client.LocalUser?.User) + return; + + client.KickUser(lastUser.Id); + } + + private void markNextPlayerReady() + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); + } + + private void markNextPlayerIdle() + { + var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready); + if (nextUnready != null) + client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle); + } + + private void performRandomAction() + { + int eventToPerform = RNG.Next(1, 6); + + switch (eventToPerform) + { + case 1: + addRandomPlayer(); + break; + + case 2: + removeLastUser(); + break; + + case 3: + kickLastUser(); + break; + + case 4: + markNextPlayerReady(); + break; + + case 5: + markNextPlayerIdle(); + break; + } + } + [Test] public void TestCreateRoomViaKeyboard() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs deleted file mode 100644 index 57ec0843b5..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLobbyEvents.cs +++ /dev/null @@ -1,218 +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 NUnit.Framework; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Platform; -using osu.Framework.Testing; -using osu.Framework.Utils; -using osu.Game.Beatmaps; -using osu.Game.Database; -using osu.Game.Online.Multiplayer; -using osu.Game.Online.Rooms; -using osu.Game.Rulesets; -using osu.Game.Rulesets.Osu; -using osu.Game.Screens; -using osu.Game.Screens.OnlinePlay.Components; -using osu.Game.Screens.OnlinePlay.Lounge; -using osu.Game.Screens.OnlinePlay.Multiplayer; -using osu.Game.Screens.OnlinePlay.Multiplayer.Match; -using osu.Game.Tests.Resources; -using osu.Game.Users; -using osuTK.Input; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneMultiplayerLobbyEvents : ScreenTestScene - { - private BeatmapManager beatmaps; - private RulesetStore rulesets; - private BeatmapSetInfo importedSet; - - private DependenciesScreen dependenciesScreen; - private TestMultiplayer multiplayerScreen; - private TestMultiplayerClient client; - - private TestRequestHandlingMultiplayerRoomManager roomManager => multiplayerScreen.RoomManager; - - [Cached(typeof(UserLookupCache))] - private UserLookupCache lookupCache = new TestUserLookupCache(); - - [BackgroundDependencyLoader] - private void load(GameHost host, AudioManager audio) - { - Dependencies.Cache(rulesets = new RulesetStore(ContextFactory)); - Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, ContextFactory, rulesets, null, audio, Resources, host, Beatmap.Default)); - } - - public override void SetUpSteps() - { - base.SetUpSteps(); - - AddStep("import beatmap", () => - { - beatmaps.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); - importedSet = beatmaps.GetAllUsableBeatmapSetsEnumerable(IncludedDetails.All).First(); - }); - - AddStep("create multiplayer screen", () => multiplayerScreen = new TestMultiplayer()); - - AddStep("load dependencies", () => - { - client = new TestMultiplayerClient(roomManager); - - // The screen gets suspended so it stops receiving updates. - Child = client; - - LoadScreen(dependenciesScreen = new DependenciesScreen(client)); - }); - - AddUntilStep("wait for dependencies to load", () => dependenciesScreen.IsLoaded); - - AddStep("load multiplayer", () => LoadScreen(multiplayerScreen)); - AddUntilStep("wait for multiplayer to load", () => multiplayerScreen.IsLoaded); - AddUntilStep("wait for lounge to load", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - } - - [Test] - public void TestLobbyEvents() - { - createRoom(() => new Room - { - Name = { Value = "Test Room" }, - Playlist = - { - new PlaylistItem - { - Beatmap = { Value = beatmaps.GetWorkingBeatmap(importedSet.Beatmaps.First(b => b.RulesetID == 0)).BeatmapInfo }, - Ruleset = { Value = new OsuRuleset().RulesetInfo }, - } - } - }); - } - - private void playerJoin() - { - int randomUser = RNG.Next(200000, 500000); - client.AddUser(new User { Id = randomUser, Username = $"user {randomUser}" }); - } - - private void playerLeave() - { - User lastUser = client.Room?.Users.Last().User; - - if (lastUser == null || lastUser == client.LocalUser?.User) - return; - - client.RemoveUser(lastUser); - } - - private void playerKicked() - { - User lastUser = client.Room?.Users.Last().User; - - if (lastUser == null || lastUser == client.LocalUser?.User) - return; - - client.KickUser(lastUser.Id); - } - - private void playerReady() - { - var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); - if (nextUnready != null) - client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); - } - - private void playerUnready() - { - var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Ready); - if (nextUnready != null) - client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Idle); - } - - private void randomEvent() - { - int eventToPerform = RNG.Next(1, 6); - - switch (eventToPerform) - { - case 1: - playerJoin(); - break; - - case 2: - playerLeave(); - break; - - case 3: - playerKicked(); - break; - - case 4: - playerReady(); - break; - - case 5: - playerUnready(); - break; - } - } - - private void createRoom(Func room) - { - AddUntilStep("wait for lounge", () => multiplayerScreen.ChildrenOfType().SingleOrDefault()?.IsLoaded == true); - AddStep("open room", () => multiplayerScreen.ChildrenOfType().Single().Open(room())); - - AddUntilStep("wait for room open", () => this.ChildrenOfType().FirstOrDefault()?.IsLoaded == true); - AddWaitStep("wait for transition", 2); - - AddStep("create room", () => - { - InputManager.MoveMouseTo(this.ChildrenOfType().Single()); - InputManager.Click(MouseButton.Left); - }); - - AddUntilStep("wait for join", () => client.Room != null); - - AddRepeatStep("random stuff happens", randomEvent, 30); - - // ensure we have a handful of players so the ready-up sounds good :9 - AddRepeatStep("player joins", playerJoin, 5); - - // all ready - AddUntilStep("all players ready", () => - { - var nextUnready = client.Room?.Users.FirstOrDefault(c => c.State == MultiplayerUserState.Idle); - if (nextUnready != null) - client.ChangeUserState(nextUnready.UserID, MultiplayerUserState.Ready); - - return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true; - }); - } - - /// - /// Used for the sole purpose of adding as a resolvable dependency. - /// - private class DependenciesScreen : OsuScreen - { - [Cached(typeof(MultiplayerClient))] - public readonly TestMultiplayerClient Client; - - public DependenciesScreen(TestMultiplayerClient client) - { - Client = client; - } - } - - private class TestMultiplayer : Screens.OnlinePlay.Multiplayer.Multiplayer - { - public new TestRequestHandlingMultiplayerRoomManager RoomManager { get; private set; } - - protected override RoomManager CreateRoomManager() => RoomManager = new TestRequestHandlingMultiplayerRoomManager(); - } - } -} From 2b06dacd0e34493461bfdabcedd9984dbf169fd9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 18:57:18 +0900 Subject: [PATCH 655/961] Change debounce back to using scheduler Should better allow for adjusting in the future, as well. --- .../Match/MultiplayerReadyButton.cs | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs index 9c818fc070..b854b6d964 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Match/MultiplayerReadyButton.cs @@ -8,6 +8,7 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Graphics.Backgrounds; using osu.Game.Online.API; @@ -38,12 +39,13 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match private Sample sampleReady; private Sample sampleReadyAll; private Sample sampleUnready; - private double unreadyLastPlaybackTime; private readonly ButtonWithTrianglesExposed button; private int countReady; + private ScheduledDelegate readySampleDelegate; + public MultiplayerReadyButton() { InternalChild = button = new ButtonWithTrianglesExposed @@ -63,8 +65,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match sampleReady = audio.Samples.Get(@"Multiplayer/player-ready"); sampleReadyAll = audio.Samples.Get(@"Multiplayer/player-ready-all"); sampleUnready = audio.Samples.Get(@"Multiplayer/player-unready"); - - unreadyLastPlaybackTime = Time.Current; } protected override void OnRoomUpdated() @@ -117,24 +117,23 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Match if (newCountReady == countReady) return; - if (newCountReady > countReady) + readySampleDelegate?.Cancel(); + readySampleDelegate = Schedule(() => { - if (newCountReady == newCountTotal) - sampleReadyAll?.Play(); - else - sampleReady?.Play(); - } - else - { - // debounce sample playback to prevent the mass-unready of game mode changes from deafening players - if (Time.Current - unreadyLastPlaybackTime > 10) + if (newCountReady > countReady) + { + if (newCountReady == newCountTotal) + sampleReadyAll?.Play(); + else + sampleReady?.Play(); + } + else if (newCountReady < countReady) { sampleUnready?.Play(); - unreadyLastPlaybackTime = Time.Current; } - } - countReady = newCountReady; + countReady = newCountReady; + }); } private void updateButtonColour(bool green) From 97f27897b13ba271ca89db32a2126a754629abe8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 18:57:35 +0900 Subject: [PATCH 656/961] Add test coverage of mass multiplayer event firing --- .../Visual/Multiplayer/TestSceneMultiplayer.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index d84fe4b6fb..22338bad84 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -125,6 +126,20 @@ namespace osu.Game.Tests.Visual.Multiplayer return client.Room?.Users.All(u => u.State == MultiplayerUserState.Ready) == true; }); + + AddStep("unready all players at once", () => + { + Debug.Assert(client.Room != null); + + foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Idle); + }); + + AddStep("ready all players at once", () => + { + Debug.Assert(client.Room != null); + + foreach (var u in client.Room.Users) client.ChangeUserState(u.UserID, MultiplayerUserState.Ready); + }); } private void addRandomPlayer() From b7a031619460698faa284ab71b5b4668775ab00d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 27 Aug 2021 13:14:56 +0300 Subject: [PATCH 657/961] Shorten test player count to 4 for less steps --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index c3be5c56ef..6f6769bdb8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -319,18 +319,18 @@ namespace osu.Game.Tests.Visual.Multiplayer [Test] public void TestPlayersLeaveWhileSpectating() { - start(getPlayerIds(8)); - sendFrames(getPlayerIds(8), 300); + start(getPlayerIds(4)); + sendFrames(getPlayerIds(4), 300); loadSpectateScreen(); - for (int count = 7; count >= 0; count--) + for (int count = 3; count >= 0; count--) { var id = PLAYER_1_ID + count; end(id); - AddUntilStep("player area grayed", () => getInstance(id).Colour != Color4.White); - AddUntilStep("score quit set", () => getLeaderboardScore(id).HasQuit.Value); + AddUntilStep($"{id} area grayed", () => getInstance(id).Colour != Color4.White); + AddUntilStep($"{id} score quit set", () => getLeaderboardScore(id).HasQuit.Value); sendFrames(getPlayerIds(count), 300); } } From 1650fbb8be04d4a0c7deeb805651803d956fcfe1 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 27 Aug 2021 13:15:12 +0300 Subject: [PATCH 658/961] Add failing test steps --- .../Multiplayer/TestSceneMultiSpectatorScreen.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs index 6f6769bdb8..bfcb55ce33 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs @@ -333,6 +333,17 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep($"{id} score quit set", () => getLeaderboardScore(id).HasQuit.Value); sendFrames(getPlayerIds(count), 300); } + + Player player = null; + + AddStep($"get {PLAYER_1_ID} player instance", () => player = getInstance(PLAYER_1_ID).ChildrenOfType().Single()); + + start(new[] { PLAYER_1_ID }); + sendFrames(PLAYER_1_ID, 300); + + AddAssert($"{PLAYER_1_ID} player instance still same", () => getInstance(PLAYER_1_ID).ChildrenOfType().Single() == player); + AddAssert($"{PLAYER_1_ID} area still grayed", () => getInstance(PLAYER_1_ID).Colour != Color4.White); + AddAssert($"{PLAYER_1_ID} score quit still set", () => getLeaderboardScore(PLAYER_1_ID).HasQuit.Value); } private void loadSpectateScreen(bool waitForPlayerLoad = true) From 378734a7f8cdd6678fcc42886f99bacfcfefcba6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Fri, 27 Aug 2021 13:16:08 +0300 Subject: [PATCH 659/961] Separate solo spectator player and "exit on restart" logic to own class --- osu.Game/Screens/Play/SoloSpectator.cs | 2 +- osu.Game/Screens/Play/SoloSpectatorPlayer.cs | 52 +++++++++++++++++++ osu.Game/Screens/Play/SpectatorPlayer.cs | 30 +++-------- .../Screens/Play/SpectatorPlayerLoader.cs | 7 +-- 4 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 osu.Game/Screens/Play/SoloSpectatorPlayer.cs diff --git a/osu.Game/Screens/Play/SoloSpectator.cs b/osu.Game/Screens/Play/SoloSpectator.cs index 820d776e63..4520e2e825 100644 --- a/osu.Game/Screens/Play/SoloSpectator.cs +++ b/osu.Game/Screens/Play/SoloSpectator.cs @@ -211,7 +211,7 @@ namespace osu.Game.Screens.Play Beatmap.Value = gameplayState.Beatmap; Ruleset.Value = gameplayState.Ruleset.RulesetInfo; - this.Push(new SpectatorPlayerLoader(gameplayState.Score)); + this.Push(new SpectatorPlayerLoader(gameplayState.Score, () => new SoloSpectatorPlayer(gameplayState.Score))); } } diff --git a/osu.Game/Screens/Play/SoloSpectatorPlayer.cs b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs new file mode 100644 index 0000000000..969a5bf2b4 --- /dev/null +++ b/osu.Game/Screens/Play/SoloSpectatorPlayer.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Screens; +using osu.Game.Online.Spectator; +using osu.Game.Scoring; + +namespace osu.Game.Screens.Play +{ + public class SoloSpectatorPlayer : SpectatorPlayer + { + private readonly Score score; + + public SoloSpectatorPlayer(Score score, PlayerConfiguration configuration = null) + : base(score, configuration) + { + this.score = score; + } + + [BackgroundDependencyLoader] + private void load() + { + SpectatorClient.OnUserBeganPlaying += userBeganPlaying; + } + + public override bool OnExiting(IScreen next) + { + SpectatorClient.OnUserBeganPlaying -= userBeganPlaying; + + return base.OnExiting(next); + } + + private void userBeganPlaying(int userId, SpectatorState state) + { + if (userId != score.ScoreInfo.UserID) return; + + Schedule(() => + { + if (this.IsCurrentScreen()) this.Exit(); + }); + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (SpectatorClient != null) + SpectatorClient.OnUserBeganPlaying -= userBeganPlaying; + } + } +} diff --git a/osu.Game/Screens/Play/SpectatorPlayer.cs b/osu.Game/Screens/Play/SpectatorPlayer.cs index 1dae28092a..d7e42a9cd1 100644 --- a/osu.Game/Screens/Play/SpectatorPlayer.cs +++ b/osu.Game/Screens/Play/SpectatorPlayer.cs @@ -14,16 +14,16 @@ using osu.Game.Screens.Ranking; namespace osu.Game.Screens.Play { - public class SpectatorPlayer : Player + public abstract class SpectatorPlayer : Player { [Resolved] - private SpectatorClient spectatorClient { get; set; } + protected SpectatorClient SpectatorClient { get; private set; } private readonly Score score; protected override bool CheckModsAllowFailure() => false; // todo: better support starting mid-way through beatmap - public SpectatorPlayer(Score score, PlayerConfiguration configuration = null) + protected SpectatorPlayer(Score score, PlayerConfiguration configuration = null) : base(configuration) { this.score = score; @@ -32,8 +32,6 @@ namespace osu.Game.Screens.Play [BackgroundDependencyLoader] private void load() { - spectatorClient.OnUserBeganPlaying += userBeganPlaying; - AddInternal(new OsuSpriteText { Text = $"Watching {score.ScoreInfo.User.Username} playing live!", @@ -50,7 +48,7 @@ namespace osu.Game.Screens.Play // Start gameplay along with the very first arrival frame (the latest one). score.Replay.Frames.Clear(); - spectatorClient.OnNewFrames += userSentFrames; + SpectatorClient.OnNewFrames += userSentFrames; } private void userSentFrames(int userId, FrameDataBundle bundle) @@ -93,31 +91,17 @@ namespace osu.Game.Screens.Play public override bool OnExiting(IScreen next) { - spectatorClient.OnUserBeganPlaying -= userBeganPlaying; - spectatorClient.OnNewFrames -= userSentFrames; + SpectatorClient.OnNewFrames -= userSentFrames; return base.OnExiting(next); } - private void userBeganPlaying(int userId, SpectatorState state) - { - if (userId != score.ScoreInfo.UserID) return; - - Schedule(() => - { - if (this.IsCurrentScreen()) this.Exit(); - }); - } - protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - if (spectatorClient != null) - { - spectatorClient.OnUserBeganPlaying -= userBeganPlaying; - spectatorClient.OnNewFrames -= userSentFrames; - } + if (SpectatorClient != null) + SpectatorClient.OnNewFrames -= userSentFrames; } } } diff --git a/osu.Game/Screens/Play/SpectatorPlayerLoader.cs b/osu.Game/Screens/Play/SpectatorPlayerLoader.cs index bdd23962dc..10cc36c9a9 100644 --- a/osu.Game/Screens/Play/SpectatorPlayerLoader.cs +++ b/osu.Game/Screens/Play/SpectatorPlayerLoader.cs @@ -11,12 +11,7 @@ namespace osu.Game.Screens.Play { public readonly ScoreInfo Score; - public SpectatorPlayerLoader(Score score) - : this(score, () => new SpectatorPlayer(score)) - { - } - - public SpectatorPlayerLoader(Score score, Func createPlayer) + public SpectatorPlayerLoader(Score score, Func createPlayer) : base(createPlayer) { if (score.Replay == null) From 804ca88d63821e88badff1ff9ff48d76c300bae5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 27 Aug 2021 19:51:51 +0900 Subject: [PATCH 660/961] Update framework --- osu.Android.props | 2 +- osu.Game/Audio/PreviewTrackManager.cs | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index f68d7124a9..be29bad31d 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/Audio/PreviewTrackManager.cs b/osu.Game/Audio/PreviewTrackManager.cs index dab5fcbe5f..1de9e1561f 100644 --- a/osu.Game/Audio/PreviewTrackManager.cs +++ b/osu.Game/Audio/PreviewTrackManager.cs @@ -35,7 +35,7 @@ namespace osu.Game.Audio { // this is a temporary solution to get around muting ourselves. // todo: update this once we have a BackgroundTrackManager or similar. - trackStore = new PreviewTrackStore(audioManager.Mixer, new OnlineStore()); + trackStore = new PreviewTrackStore(audioManager.TrackMixer, new OnlineStore()); audio.AddItem(trackStore); trackStore.AddAdjustment(AdjustableProperty.Volume, globalTrackVolumeAdjust); diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 8e39c5a3df..21d10d650c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 0e3e87f3c1..62924ba391 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 681a87d4ec516fac98d65d3123ffcb7b636c6ed8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 07:08:06 +0900 Subject: [PATCH 661/961] 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 be29bad31d..f18400bf2f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 21d10d650c..a89d57cd1f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 62924ba391..bb4700a081 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From e527bfd4bf4d36cf71a6871828a129760e7efabc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 Aug 2021 02:37:46 +0300 Subject: [PATCH 662/961] Move incompatibility icon logic to local player mod select overlays --- .../Overlays/Mods/LocalPlayerModButton.cs | 69 +++++++++++++++++++ .../Mods/LocalPlayerModSelectOverlay.cs | 12 ++++ osu.Game/Overlays/Mods/ModButton.cs | 55 +++------------ osu.Game/Overlays/Mods/ModSection.cs | 10 +-- 4 files changed, 96 insertions(+), 50 deletions(-) create mode 100644 osu.Game/Overlays/Mods/LocalPlayerModButton.cs diff --git a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs new file mode 100644 index 0000000000..10c81da7a6 --- /dev/null +++ b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs @@ -0,0 +1,69 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; +using osu.Game.Utils; +using osuTK; + +namespace osu.Game.Overlays.Mods +{ + public class LocalPlayerModButton : ModButton + { + private readonly CompositeDrawable incompatibleIcon; + + [Resolved] + private Bindable> selectedMods { get; set; } + + public LocalPlayerModButton(Mod mod) + : base(mod) + { + ButtonContent.Add(incompatibleIcon = new IncompatibleIcon + { + Anchor = Anchor.BottomRight, + Origin = Anchor.Centre, + Position = new Vector2(-13), + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true); + } + + protected override void DisplayMod(Mod mod) + { + base.DisplayMod(mod); + + Scheduler.AddOnce(updateCompatibility); + } + + private void updateCompatibility() + { + var m = SelectedMod ?? Mods.First(); + + bool isIncompatible = false; + + if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m)) + isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m)); + + if (isIncompatible) + incompatibleIcon.Show(); + else + incompatibleIcon.Hide(); + } + } +} diff --git a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs b/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs index db76581108..b8e0c27007 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs @@ -14,5 +14,17 @@ namespace osu.Game.Overlays.Mods foreach (var section in ModSectionsContainer.Children) section.DeselectTypes(mod.IncompatibleMods, true, mod); } + + protected override ModSection CreateModSection(ModType type) => new LocalPlayerModSection(type); + + private class LocalPlayerModSection : ModSection + { + public LocalPlayerModSection(ModType type) + : base(type) + { + } + + protected override ModButton CreateModButton(Mod mod) => new LocalPlayerModButton(mod); + } } } diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 4675eb6bc8..8f6fc734e8 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -11,16 +11,12 @@ using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using System; -using System.Collections.Generic; using System.Linq; -using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics.Cursor; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; -using osu.Game.Utils; namespace osu.Game.Overlays.Mods { @@ -33,7 +29,6 @@ namespace osu.Game.Overlays.Mods private ModIcon backgroundIcon; private readonly SpriteText text; private readonly Container iconsContainer; - private readonly CompositeDrawable incompatibleIcon; /// /// Fired when the selection changes. @@ -48,9 +43,6 @@ namespace osu.Game.Overlays.Mods // A selected index of -1 means not selected. private int selectedIndex = -1; - [Resolved] - private Bindable> selectedMods { get; set; } - /// /// Change the selected mod index of this button. /// @@ -109,7 +101,7 @@ namespace osu.Game.Overlays.Mods .RotateTo(rotate_angle * direction) .RotateTo(0f, mod_switch_duration, mod_switch_easing); - Schedule(() => displayMod(newSelection)); + Schedule(() => DisplayMod(newSelection)); } } @@ -138,7 +130,8 @@ namespace osu.Game.Overlays.Mods } private Mod mod; - private readonly Container scaleContainer; + + protected readonly Container ButtonContent; public Mod Mod { @@ -162,7 +155,7 @@ namespace osu.Game.Overlays.Mods if (Mods.Length > 0) { - displayMod(Mods[0]); + DisplayMod(Mods[0]); } } } @@ -173,13 +166,13 @@ namespace osu.Game.Overlays.Mods protected override bool OnMouseDown(MouseDownEvent e) { - scaleContainer.ScaleTo(0.9f, 800, Easing.Out); + ButtonContent.ScaleTo(0.9f, 800, Easing.Out); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - scaleContainer.ScaleTo(1, 500, Easing.OutElastic); + ButtonContent.ScaleTo(1, 500, Easing.OutElastic); // only trigger the event if we are inside the area of the button if (Contains(e.ScreenSpaceMousePosition)) @@ -238,30 +231,13 @@ namespace osu.Game.Overlays.Mods public void Deselect() => changeSelectedIndex(-1); - private void displayMod(Mod mod) + protected virtual void DisplayMod(Mod mod) { if (backgroundIcon != null) backgroundIcon.Mod = foregroundIcon.Mod; foregroundIcon.Mod = mod; text.Text = mod.Name; Colour = mod.HasImplementation ? Color4.White : Color4.Gray; - - Scheduler.AddOnce(updateCompatibility); - } - - private void updateCompatibility() - { - var m = SelectedMod ?? Mods.First(); - - bool isIncompatible = false; - - if (selectedMods.Value.Count > 0 && !selectedMods.Value.Contains(m)) - isIncompatible = !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(m)); - - if (isIncompatible) - incompatibleIcon.Show(); - else - incompatibleIcon.Hide(); } private void createIcons() @@ -307,7 +283,7 @@ namespace osu.Game.Overlays.Mods Anchor = Anchor.TopCentre, Children = new Drawable[] { - scaleContainer = new Container + ButtonContent = new Container { Children = new Drawable[] { @@ -317,12 +293,6 @@ namespace osu.Game.Overlays.Mods Origin = Anchor.Centre, Anchor = Anchor.Centre, }, - incompatibleIcon = new IncompatibleIcon - { - Origin = Anchor.Centre, - Anchor = Anchor.BottomRight, - Position = new Vector2(-13), - } }, RelativeSizeAxes = Axes.Both, Origin = Anchor.Centre, @@ -342,14 +312,7 @@ namespace osu.Game.Overlays.Mods Mod = mod; } - protected override void LoadComplete() - { - base.LoadComplete(); - - selectedMods.BindValueChanged(_ => Scheduler.AddOnce(updateCompatibility), true); - } - - public ITooltip GetCustomTooltip() => new ModButtonTooltip(); + public virtual ITooltip GetCustomTooltip() => new ModButtonTooltip(); public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault(); } diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index 6e289dc8aa..faad23a4e1 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -51,14 +51,14 @@ namespace osu.Game.Overlays.Mods if (m == null) return new ModButtonEmpty(); - return new ModButton(m) + return CreateModButton(m).With(b => { - SelectionChanged = mod => + b.SelectionChanged = mod => { ModButtonStateChanged(mod); Action?.Invoke(mod); - }, - }; + }; + }); }).ToArray(); modsLoadCts?.Cancel(); @@ -247,6 +247,8 @@ namespace osu.Game.Overlays.Mods Text = text }; + protected virtual ModButton CreateModButton(Mod mod) => new ModButton(mod); + /// /// Play out all remaining animations immediately to leave mods in a good (final) state. /// From 589f2863ca16b75a959a873d1f4c6a1517107ede Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 Aug 2021 02:38:45 +0300 Subject: [PATCH 663/961] Move incompatibility tooltip logic to local player mod select overlays This one turned out to be a bit more involved, due to tooltips being shared and having the potential of being used somewhere where it shouldn't be, due to the same content type matching. That's the reason I've defined a protected `TargetContentType`, to be able to separate "local player mod tooltips" and regular mod tooltips apart. Definitely unsure about the solution, but that's as far as I can think of right now. --- .../Overlays/Mods/LocalPlayerModButton.cs | 51 ++++++++++++++++ osu.Game/Overlays/Mods/ModButton.cs | 2 +- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 58 +++++-------------- 3 files changed, 68 insertions(+), 43 deletions(-) diff --git a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs index 10c81da7a6..9427c3e63e 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs +++ b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs @@ -65,5 +65,56 @@ namespace osu.Game.Overlays.Mods else incompatibleIcon.Hide(); } + + public override ITooltip GetCustomTooltip() => new LocalPlayerModButtonTooltip(); + + private class LocalPlayerModButtonTooltip : ModButtonTooltip + { + private readonly OsuSpriteText incompatibleText; + + private readonly Bindable> incompatibleMods = new Bindable>(); + + [Resolved] + private Bindable ruleset { get; set; } + + public LocalPlayerModButtonTooltip() + { + AddRange(new Drawable[] + { + incompatibleText = new OsuSpriteText + { + Margin = new MarginPadding { Top = 5 }, + Font = OsuFont.GetFont(weight: FontWeight.Regular), + Text = "Incompatible with:" + }, + new ModDisplay + { + Current = incompatibleMods, + ExpansionMode = ExpansionMode.AlwaysExpanded, + Scale = new Vector2(0.7f) + } + }); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + incompatibleText.Colour = colours.BlueLight; + } + + protected override Type TargetContentType => typeof(LocalPlayerModButton); + + protected override void UpdateDisplay(Mod mod) + { + base.UpdateDisplay(mod); + + var incompatibleTypes = mod.IncompatibleMods; + + var allMods = ruleset.Value.CreateInstance().GetAllMods(); + + incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); + incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods"; + } + } } } diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index 8f6fc734e8..cc8acb7513 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -314,6 +314,6 @@ namespace osu.Game.Overlays.Mods public virtual ITooltip GetCustomTooltip() => new ModButtonTooltip(); - public object TooltipContent => SelectedMod ?? Mods.FirstOrDefault(); + public object TooltipContent => this; } } diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 666ed07e28..125357ea44 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -1,19 +1,16 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; +using System; using System.Linq; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; -using osu.Game.Screens.Play.HUD; using osuTK; namespace osu.Game.Overlays.Mods @@ -22,12 +19,8 @@ namespace osu.Game.Overlays.Mods { private readonly OsuSpriteText descriptionText; private readonly Box background; - private readonly OsuSpriteText incompatibleText; - private readonly Bindable> incompatibleMods = new Bindable>(); - - [Resolved] - private Bindable ruleset { get; set; } + protected override Container Content { get; } public ModButtonTooltip() { @@ -35,13 +28,13 @@ namespace osu.Game.Overlays.Mods Masking = true; CornerRadius = 5; - Children = new Drawable[] + InternalChildren = new Drawable[] { background = new Box { RelativeSizeAxes = Axes.Both }, - new FillFlowContainer + Content = new FillFlowContainer { AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, @@ -51,19 +44,7 @@ namespace osu.Game.Overlays.Mods descriptionText = new OsuSpriteText { Font = OsuFont.GetFont(weight: FontWeight.Regular), - Margin = new MarginPadding { Bottom = 5 } }, - incompatibleText = new OsuSpriteText - { - Font = OsuFont.GetFont(weight: FontWeight.Regular), - Text = "Incompatible with:" - }, - new ModDisplay - { - Current = incompatibleMods, - ExpansionMode = ExpansionMode.AlwaysExpanded, - Scale = new Vector2(0.7f) - } } }, }; @@ -74,7 +55,6 @@ namespace osu.Game.Overlays.Mods { background.Colour = colours.Gray3; descriptionText.Colour = colours.BlueLighter; - incompatibleText.Colour = colours.BlueLight; } protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); @@ -82,34 +62,28 @@ namespace osu.Game.Overlays.Mods private Mod lastMod; - public bool SetContent(object content) + protected virtual Type TargetContentType => typeof(ModButton); + + public virtual bool SetContent(object content) { - if (!(content is Mod mod)) + if (!(content is ModButton button) || content.GetType() != TargetContentType) return false; + var mod = button.SelectedMod ?? button.Mods.First(); + if (mod.Equals(lastMod)) return true; lastMod = mod; - descriptionText.Text = mod.Description; - - var incompatibleTypes = mod.IncompatibleMods; - - var allMods = ruleset.Value.CreateInstance().GetAllMods(); - - incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); - - if (!incompatibleMods.Value.Any()) - { - incompatibleText.Text = "Compatible with all mods"; - return true; - } - - incompatibleText.Text = "Incompatible with:"; - + UpdateDisplay(mod); return true; } + protected virtual void UpdateDisplay(Mod mod) + { + descriptionText.Text = mod.Description; + } + public void Move(Vector2 pos) => Position = pos; } } From 7fbeb9ecc7a78fed1ef88d45b42eed54d13a19d7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 14:15:47 +0900 Subject: [PATCH 664/961] Add failing test coverage for tournament startup states --- .../Screens/TestSceneGameplayScreen.cs | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs index 2e34c39370..7002db781e 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs @@ -4,8 +4,10 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Tournament.Components; +using osu.Game.Tournament.IPC; using osu.Game.Tournament.Screens.Gameplay; using osu.Game.Tournament.Screens.Gameplay.Components; @@ -16,16 +18,18 @@ namespace osu.Game.Tournament.Tests.Screens [Cached] private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f }; - [BackgroundDependencyLoader] - private void load() + [Test] + public void TestStartupState([Values] TourneyState state) { - Add(new GameplayScreen()); - Add(chat); + AddStep("set state", () => IPCInfo.State.Value = state); + createScreen(); } [Test] public void TestWarmup() { + createScreen(); + checkScoreVisibility(false); toggleWarmup(); @@ -35,6 +39,20 @@ namespace osu.Game.Tournament.Tests.Screens checkScoreVisibility(false); } + private void createScreen() + { + AddStep("setup screen", () => + { + Remove(chat); + + Children = new Drawable[] + { + new GameplayScreen(), + chat, + }; + }); + } + private void checkScoreVisibility(bool visible) => AddUntilStep($"scores {(visible ? "shown" : "hidden")}", () => this.ChildrenOfType().All(score => score.Alpha == (visible ? 1 : 0))); From e9b97f7937cd842ae410a5b318c76fb5aa3b791c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 14:15:42 +0900 Subject: [PATCH 665/961] Fix tournament crashing when osu!(stable) is at ranking screen at startup --- .../Screens/Gameplay/GameplayScreen.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index 540b45eb56..44a6006553 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -124,9 +124,6 @@ namespace osu.Game.Tournament.Screens.Gameplay } }); - State.BindTo(ipc.State); - State.BindValueChanged(stateChanged, true); - ladder.ChromaKeyWidth.BindValueChanged(width => chroma.Width = width.NewValue, true); warmup.BindValueChanged(w => @@ -136,6 +133,14 @@ namespace osu.Game.Tournament.Screens.Gameplay }, true); } + protected override void LoadComplete() + { + base.LoadComplete(); + + State.BindTo(ipc.State); + State.BindValueChanged(stateChanged, true); + } + protected override void CurrentMatchChanged(ValueChangedEvent match) { base.CurrentMatchChanged(match); From 303c70791d646858a8c53c9ed32bce7291bf8858 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 16:22:01 +0900 Subject: [PATCH 666/961] Add more failing test coverage for `null` `CurrentMatch` --- .../Screens/TestSceneGameplayScreen.cs | 8 ++++++++ .../Screens/TestSceneTeamWinScreen.cs | 5 +++-- osu.Game.Tournament.Tests/TournamentTestScene.cs | 12 +++++++++--- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs index 7002db781e..6879a71f1d 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneGameplayScreen.cs @@ -25,6 +25,14 @@ namespace osu.Game.Tournament.Tests.Screens createScreen(); } + [Test] + public void TestStartupStateNoCurrentMatch([Values] TourneyState state) + { + AddStep("set null current", () => Ladder.CurrentMatch.Value = null); + AddStep("set state", () => IPCInfo.State.Value = state); + createScreen(); + } + [Test] public void TestWarmup() { diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs index 3ca58dcaf4..4de576b3b0 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs @@ -2,6 +2,7 @@ // 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.Game.Tournament.Screens.TeamWin; @@ -10,8 +11,8 @@ namespace osu.Game.Tournament.Tests.Screens { public class TestSceneTeamWinScreen : TournamentTestScene { - [BackgroundDependencyLoader] - private void load() + [Test] + public void TestBasic() { var match = Ladder.CurrentMatch.Value; diff --git a/osu.Game.Tournament.Tests/TournamentTestScene.cs b/osu.Game.Tournament.Tests/TournamentTestScene.cs index 1fa0ffc8e9..93e1e018a5 100644 --- a/osu.Game.Tournament.Tests/TournamentTestScene.cs +++ b/osu.Game.Tournament.Tests/TournamentTestScene.cs @@ -19,6 +19,8 @@ namespace osu.Game.Tournament.Tests { public abstract class TournamentTestScene : OsuTestScene { + private TournamentMatch match; + [Cached] protected LadderInfo Ladder { get; private set; } = new LadderInfo(); @@ -33,19 +35,23 @@ namespace osu.Game.Tournament.Tests { Ladder.Ruleset.Value ??= rulesetStore.AvailableRulesets.First(); - TournamentMatch match = CreateSampleMatch(); + match = CreateSampleMatch(); Ladder.Rounds.Add(match.Round.Value); Ladder.Matches.Add(match); Ladder.Teams.Add(match.Team1.Value); Ladder.Teams.Add(match.Team2.Value); - Ladder.CurrentMatch.Value = match; - Ruleset.BindTo(Ladder.Ruleset); Dependencies.CacheAs(new StableInfo(storage)); } + [SetUpSteps] + public virtual void SetUpSteps() + { + AddStep("set current match", () => Ladder.CurrentMatch.Value = match); + } + public static TournamentMatch CreateSampleMatch() => new TournamentMatch { Team1 = From 6ef096001e00b725810d0987703adb795b874fc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 16:22:12 +0900 Subject: [PATCH 667/961] Fix several cases of incorrect handling of `CurrentMatch` nullability --- .../Screens/Gameplay/Components/MatchRoundDisplay.cs | 2 +- osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs index 87793f7e1b..2f0e4b5e87 100644 --- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs +++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs @@ -20,6 +20,6 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components } private void matchChanged(ValueChangedEvent match) => - Text.Text = match.NewValue.Round.Value?.Name.Value ?? "Unknown Round"; + Text.Text = match.NewValue?.Round.Value?.Name.Value ?? "Unknown Round"; } } diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs index 44a6006553..7e7c719152 100644 --- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs +++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs @@ -164,7 +164,7 @@ namespace osu.Game.Tournament.Screens.Gameplay { if (state.NewValue == TourneyState.Ranking) { - if (warmup.Value) return; + if (warmup.Value || CurrentMatch.Value == null) return; if (ipc.Score1.Value > ipc.Score2.Value) CurrentMatch.Value.Team1Score.Value++; From b008a86d8c0904a05a847ea27101c98a3336a825 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 28 Aug 2021 16:35:54 +0900 Subject: [PATCH 668/961] Remove unused using statement --- osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs index 4de576b3b0..2c8610b414 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs @@ -3,7 +3,6 @@ using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Tournament.Screens.TeamWin; From d37df6afeca4e2a1fff47a521dec9d7ab6997adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 09:44:54 +0200 Subject: [PATCH 669/961] Fix test failing after BDL -> `[Test]` change --- .../Screens/TestSceneTeamWinScreen.cs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs index 2c8610b414..d07cc4c431 100644 --- a/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs +++ b/osu.Game.Tournament.Tests/Screens/TestSceneTeamWinScreen.cs @@ -13,16 +13,19 @@ namespace osu.Game.Tournament.Tests.Screens [Test] public void TestBasic() { - var match = Ladder.CurrentMatch.Value; + AddStep("set up match", () => + { + var match = Ladder.CurrentMatch.Value; - match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals"); - match.Completed.Value = true; + match.Round.Value = Ladder.Rounds.FirstOrDefault(g => g.Name.Value == "Finals"); + match.Completed.Value = true; + }); - Add(new TeamWinScreen + AddStep("create screen", () => Add(new TeamWinScreen { FillMode = FillMode.Fit, FillAspectRatio = 16 / 9f - }); + })); } } } From eb90cedc9bafc230180bd5fa260b1067859f1d9d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 Aug 2021 20:09:35 +0300 Subject: [PATCH 670/961] Fix editor screen test scenes not updated to show their screens --- osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs | 6 +++++- osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs | 7 ++++++- osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs index 6f5655006e..4813598c9d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneComposeScreen.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; @@ -30,7 +31,10 @@ namespace osu.Game.Tests.Visual.Editing { Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); - Child = new ComposeScreen(); + Child = new ComposeScreen + { + State = { Value = Visibility.Visible }, + }; } } } diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs index 62e12158ab..9253023c9a 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Screens.Edit; @@ -26,7 +27,11 @@ namespace osu.Game.Tests.Visual.Editing private void load() { Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); - Child = new SetupScreen(); + + Child = new SetupScreen + { + State = { Value = Visibility.Visible }, + }; } } } diff --git a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs index b82e776164..f961fff1e5 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneTimingScreen.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; @@ -30,7 +31,10 @@ namespace osu.Game.Tests.Visual.Editing Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); Beatmap.Disabled = true; - Child = new TimingScreen(); + Child = new TimingScreen + { + State = { Value = Visibility.Visible }, + }; } protected override void Dispose(bool isDisposing) From 7457480b50c9a69c01287feec8dff1b08b6b15db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 18:47:34 +0200 Subject: [PATCH 671/961] Add local popover container to lounge subscreen --- osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs index cf3d76a3fb..cca1394b6d 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/LoungeSubScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; using osu.Framework.Logging; @@ -72,6 +73,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge private readonly Bindable filter = new Bindable(new FilterCriteria()); private readonly IBindable operationInProgress = new Bindable(); private readonly IBindable isIdle = new BindableBool(); + private PopoverContainer popoverContainer; private LoadingLayer loadingLayer; private RoomsContainer roomsContainer; private SearchTextBox searchTextBox; @@ -90,7 +92,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge InternalChildren = new Drawable[] { ListingPollingComponent = CreatePollingComponent().With(c => c.Filter.BindTarget = filter), - new Container + popoverContainer = new PopoverContainer { Name = @"Rooms area", RelativeSizeAxes = Axes.Both, @@ -285,7 +287,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge searchTextBox.HoldFocus = false; // ensure any password prompt is dismissed. - this.HidePopover(); + popoverContainer.HidePopover(); } public void Join(Room room, string password) => Schedule(() => From e94d96f25093a2b32511554548e1a1314db6ce45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 18:49:24 +0200 Subject: [PATCH 672/961] Add local popover container to editor screens --- osu.Game/Screens/Edit/EditorScreen.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index d7fe5207d0..5665e6cb55 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; namespace osu.Game.Screens.Edit { @@ -28,7 +29,7 @@ namespace osu.Game.Screens.Edit Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; - InternalChild = content = new Container { RelativeSizeAxes = Axes.Both }; + InternalChild = content = new PopoverContainer { RelativeSizeAxes = Axes.Both }; } protected override void PopIn() From fcc3e57d5dd86d82f0d9c56e6c4c5fa67fe3ef9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 18:50:13 +0200 Subject: [PATCH 673/961] Move overlay colour provider up to editor screen --- osu.Game/Screens/Edit/EditorRoundedScreen.cs | 5 ----- osu.Game/Screens/Edit/EditorScreen.cs | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorRoundedScreen.cs b/osu.Game/Screens/Edit/EditorRoundedScreen.cs index c6ced02021..b271a145f5 100644 --- a/osu.Game/Screens/Edit/EditorRoundedScreen.cs +++ b/osu.Game/Screens/Edit/EditorRoundedScreen.cs @@ -6,7 +6,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; -using osu.Game.Overlays; namespace osu.Game.Screens.Edit { @@ -17,9 +16,6 @@ namespace osu.Game.Screens.Edit [Resolved] private OsuColour colours { get; set; } - [Cached] - protected readonly OverlayColourProvider ColourProvider; - private Container roundedContent; protected override Container Content => roundedContent; @@ -27,7 +23,6 @@ namespace osu.Game.Screens.Edit public EditorRoundedScreen(EditorScreenMode mode) : base(mode) { - ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); } [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Edit/EditorScreen.cs b/osu.Game/Screens/Edit/EditorScreen.cs index 5665e6cb55..2810f78835 100644 --- a/osu.Game/Screens/Edit/EditorScreen.cs +++ b/osu.Game/Screens/Edit/EditorScreen.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Game.Overlays; namespace osu.Game.Screens.Edit { @@ -16,6 +17,9 @@ namespace osu.Game.Screens.Edit [Resolved] protected EditorBeatmap EditorBeatmap { get; private set; } + [Cached] + protected readonly OverlayColourProvider ColourProvider; + protected override Container Content => content; private readonly Container content; @@ -29,6 +33,8 @@ namespace osu.Game.Screens.Edit Origin = Anchor.Centre; RelativeSizeAxes = Axes.Both; + ColourProvider = new OverlayColourProvider(OverlayColourScheme.Blue); + InternalChild = content = new PopoverContainer { RelativeSizeAxes = Axes.Both }; } From d9db1ecee9c6183424b86881b099d732933a424c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 18:51:12 +0200 Subject: [PATCH 674/961] Remove game-global popover container --- osu.Game/OsuGameBase.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f2d575550a..69f6bc1b7b 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -13,7 +13,6 @@ using osu.Framework.Development; using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.IO.Stores; using osu.Framework.Platform; using osu.Game.Beatmaps; @@ -342,11 +341,7 @@ namespace osu.Game globalBindings = new GlobalActionContainer(this) }; - MenuCursorContainer.Child = new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both } - }; + MenuCursorContainer.Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }; base.Content.Add(CreateScalingContainer().WithChildren(mainContent)); From 2efe82a18db9c46d2502852201fea28dfb114e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 28 Aug 2021 20:20:42 +0200 Subject: [PATCH 675/961] Remove popover container from manual input manager test scene --- .../TestSceneLabelledColourPalette.cs | 21 ++++++++++++------- .../Visual/OsuManualInputManagerTestScene.cs | 7 +------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs index 6fafb8f87a..e1ea02ba67 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledColourPalette.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Cursor; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Graphics.Cursor; @@ -55,20 +56,24 @@ namespace osu.Game.Tests.Visual.UserInterface { AddStep("create component", () => { - Child = new OsuContextMenuContainer + Child = new PopoverContainer { RelativeSizeAxes = Axes.Both, - Child = new Container + Child = new OsuContextMenuContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 500, - AutoSizeAxes = Axes.Y, - Child = component = new LabelledColourPalette + RelativeSizeAxes = Axes.Both, + Child = new Container { Anchor = Anchor.Centre, Origin = Anchor.Centre, - ColourNamePrefix = "My colour #" + Width = 500, + AutoSizeAxes = Axes.Y, + Child = component = new LabelledColourPalette + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + ColourNamePrefix = "My colour #" + } } } }; diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index c5e2e67eaf..752794d25a 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -3,7 +3,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; using osu.Framework.Testing.Input; using osu.Game.Graphics.Cursor; @@ -35,11 +34,7 @@ namespace osu.Game.Tests.Visual { MenuCursorContainer cursorContainer; - CompositeDrawable mainContent = new PopoverContainer - { - RelativeSizeAxes = Axes.Both, - Child = cursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both, } - }; + CompositeDrawable mainContent = cursorContainer = new MenuCursorContainer { RelativeSizeAxes = Axes.Both }; cursorContainer.Child = content = new OsuTooltipContainer(cursorContainer.Cursor) { From 38912bfc1663db6ac5e278bc3a1b50ae1f5089bc Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 28 Aug 2021 20:13:01 -0700 Subject: [PATCH 676/961] Fix floating overlays not closing when clicking some empty area of the toolbar --- osu.Game/OsuGame.cs | 26 +++++++++++++++--------- osu.Game/Overlays/LoginOverlay.cs | 13 ------------ osu.Game/Overlays/NotificationOverlay.cs | 13 ------------ osu.Game/Overlays/NowPlayingOverlay.cs | 6 ------ osu.Game/Overlays/SettingsPanel.cs | 6 ------ 5 files changed, 16 insertions(+), 48 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4d952c39c6..a584644fc9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -104,6 +104,8 @@ namespace osu.Game protected Container ScreenOffsetContainer { get; private set; } + private Container overlayOffsetContainer; + [Resolved] private FrameworkConfigManager frameworkConfig { get; set; } @@ -120,7 +122,7 @@ namespace osu.Game public virtual StableStorage GetStorageForStableInstall() => null; - public float ToolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0); + private float toolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0); private IdleTracker idleTracker; @@ -692,9 +694,16 @@ namespace osu.Game }, } }, - overlayContent = new Container { RelativeSizeAxes = Axes.Both }, - rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, - leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, + overlayOffsetContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + overlayContent = new Container { RelativeSizeAxes = Axes.Both }, + rightFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, + leftFloatingOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, + } + }, topMostOverlayContent = new Container { RelativeSizeAxes = Axes.Both }, idleTracker, new ConfineMouseTracker() @@ -731,7 +740,6 @@ namespace osu.Game loadComponentSingleFile(Notifications.With(d => { - d.GetToolbarHeight = () => ToolbarOffset; d.Anchor = Anchor.TopRight; d.Origin = Anchor.TopRight; }), rightFloatingOverlayContent.Add, true); @@ -757,7 +765,7 @@ namespace osu.Game loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); - loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); + loadComponentSingleFile(Settings = new SettingsOverlay(), leftFloatingOverlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); loadComponentSingleFile(beatmapSetOverlay = new BeatmapSetOverlay(), overlayContent.Add, true); @@ -766,14 +774,12 @@ namespace osu.Game loadComponentSingleFile(new LoginOverlay { - GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, rightFloatingOverlayContent.Add, true); loadComponentSingleFile(new NowPlayingOverlay { - GetToolbarHeight = () => ToolbarOffset, Anchor = Anchor.TopRight, Origin = Anchor.TopRight, }, rightFloatingOverlayContent.Add, true); @@ -1013,8 +1019,8 @@ namespace osu.Game { base.UpdateAfterChildren(); - ScreenOffsetContainer.Padding = new MarginPadding { Top = ToolbarOffset }; - overlayContent.Padding = new MarginPadding { Top = ToolbarOffset }; + ScreenOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset }; + overlayOffsetContainer.Padding = new MarginPadding { Top = toolbarOffset }; var horizontalOffset = 0f; diff --git a/osu.Game/Overlays/LoginOverlay.cs b/osu.Game/Overlays/LoginOverlay.cs index d0411ba9e7..e7caaa3aca 100644 --- a/osu.Game/Overlays/LoginOverlay.cs +++ b/osu.Game/Overlays/LoginOverlay.cs @@ -10,7 +10,6 @@ using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; -using System; namespace osu.Game.Overlays { @@ -20,11 +19,6 @@ namespace osu.Game.Overlays private const float transition_time = 400; - /// - /// Provide a source for the toolbar height. - /// - public Func GetToolbarHeight; - public LoginOverlay() { AutoSizeAxes = Axes.Both; @@ -94,12 +88,5 @@ namespace osu.Game.Overlays settingsSection.Bounding = false; this.FadeOut(transition_time); } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; - } } } diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index e3956089c2..2175e17da9 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Overlays.Notifications; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; -using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Localisation; @@ -30,11 +29,6 @@ namespace osu.Game.Overlays private FlowContainer sections; - /// - /// Provide a source for the toolbar height. - /// - public Func GetToolbarHeight; - [BackgroundDependencyLoader] private void load() { @@ -168,12 +162,5 @@ namespace osu.Game.Overlays updateCounts(); } - - protected override void UpdateAfterChildren() - { - base.UpdateAfterChildren(); - - Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; - } } } diff --git a/osu.Game/Overlays/NowPlayingOverlay.cs b/osu.Game/Overlays/NowPlayingOverlay.cs index f88be91c01..5619d7b38a 100644 --- a/osu.Game/Overlays/NowPlayingOverlay.cs +++ b/osu.Game/Overlays/NowPlayingOverlay.cs @@ -55,11 +55,6 @@ namespace osu.Game.Overlays protected override string PopInSampleName => "UI/now-playing-pop-in"; protected override string PopOutSampleName => "UI/now-playing-pop-out"; - /// - /// Provide a source for the toolbar height. - /// - public Func GetToolbarHeight; - [Resolved] private MusicController musicController { get; set; } @@ -246,7 +241,6 @@ namespace osu.Game.Overlays base.UpdateAfterChildren(); Height = dragContainer.Height; - dragContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } protected override void Update() diff --git a/osu.Game/Overlays/SettingsPanel.cs b/osu.Game/Overlays/SettingsPanel.cs index 5589786169..bda4bb5ece 100644 --- a/osu.Game/Overlays/SettingsPanel.cs +++ b/osu.Game/Overlays/SettingsPanel.cs @@ -54,11 +54,6 @@ namespace osu.Game.Overlays protected override string PopInSampleName => "UI/settings-pop-in"; - /// - /// Provide a source for the toolbar height. - /// - public Func GetToolbarHeight; - private readonly bool showSidebar; private LoadingLayer loading; @@ -193,7 +188,6 @@ namespace osu.Game.Overlays base.UpdateAfterChildren(); ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 }; - Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 }; } private const double fade_in_duration = 1000; From 9a5445bdeda54f9d40a48e20a556ebd5dea0d811 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sat, 28 Aug 2021 22:25:13 -0700 Subject: [PATCH 677/961] Fix overlays closing when clicking any empty area of the toolbar instead --- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 4 ++-- osu.Game/Overlays/Toolbar/Toolbar.cs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index b9b098df80..0e635d26c2 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -75,14 +75,14 @@ namespace osu.Game.Graphics.Containers protected override bool OnMouseDown(MouseDownEvent e) { - closeOnMouseUp = !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition); + closeOnMouseUp = !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition) && (game?.Toolbar.IsHovered == false); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) + if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition) && (game?.Toolbar.IsHovered == false)) Hide(); base.OnMouseUp(e); diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 3d88171ba7..918e3b7105 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -41,6 +41,9 @@ namespace osu.Game.Overlays.Toolbar // Toolbar and its components need keyboard input even when hidden. public override bool PropagateNonPositionalInputSubTree => true; + // IsHovered is used + public override bool HandlePositionalInput => true; + public Toolbar() { RelativeSizeAxes = Axes.X; @@ -140,12 +143,13 @@ namespace osu.Game.Overlays.Toolbar protected override bool OnHover(HoverEvent e) { gradientBackground.FadeIn(transition_time, Easing.OutQuint); - return true; + return base.OnHover(e); } protected override void OnHoverLost(HoverLostEvent e) { gradientBackground.FadeOut(transition_time, Easing.OutQuint); + base.OnHoverLost(e); } } From e374ef163de240c91bff458fd59e10b62e2d91e7 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 29 Aug 2021 15:00:28 +0300 Subject: [PATCH 678/961] Update localisable formattable extensions usages inline with framework change --- osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs | 2 +- osu.Game/Overlays/BeatmapSet/BasicStats.cs | 1 + osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs | 1 + osu.Game/Overlays/BeatmapSet/SuccessRate.cs | 2 +- osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs | 1 + osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs | 1 + .../Profile/Header/Components/ProfileHeaderStatisticsButton.cs | 2 +- osu.Game/Overlays/Profile/Header/Components/RankGraph.cs | 1 + osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs | 1 + osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs | 1 + osu.Game/Overlays/Profile/Sections/CounterPill.cs | 2 +- .../Overlays/Profile/Sections/Historical/ProfileLineChart.cs | 1 + .../Overlays/Profile/Sections/Historical/UserHistoryGraph.cs | 1 + osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs | 1 + .../Profile/Sections/Ranks/DrawableProfileWeightedScore.cs | 2 +- osu.Game/Overlays/Rankings/SpotlightSelector.cs | 1 + osu.Game/Overlays/Rankings/Tables/CountriesTable.cs | 2 +- osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs | 2 +- osu.Game/Overlays/Rankings/Tables/RankingsTable.cs | 1 + osu.Game/Overlays/Rankings/Tables/ScoresTable.cs | 2 +- osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs | 1 + osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs | 1 + osu.Game/Screens/Select/Details/UserRatings.cs | 2 +- osu.Game/Utils/FormatUtils.cs | 1 + 25 files changed, 25 insertions(+), 10 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs index c239fda455..dde7680989 100644 --- a/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs +++ b/osu.Game/Beatmaps/Drawables/StarRatingDisplay.cs @@ -4,12 +4,12 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Overlays; diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs index 2dcb2f1777..5a6cde8229 100644 --- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs +++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index b16fb76ec3..60e341d2ac 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -6,12 +6,12 @@ using System.Linq; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; -using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs index c934020059..7704fa24df 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -3,6 +3,7 @@ using System; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; diff --git a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs index b1e9abe3aa..cde4589c98 100644 --- a/osu.Game/Overlays/BeatmapSet/SuccessRate.cs +++ b/osu.Game/Overlays/BeatmapSet/SuccessRate.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index f15fa2705a..180a288729 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs index 877637be22..2c8c421eba 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelProgressBar.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; diff --git a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs index 1235836aac..b098f9f840 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ProfileHeaderStatisticsButton.cs @@ -1,10 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 74a25591b4..e8bce404e1 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using Humanizer; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Localisation; using osu.Game.Graphics; diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 9e52751904..8ca6961950 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index 438f52a2ce..cf930e985c 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Overlays/Profile/Sections/CounterPill.cs b/osu.Game/Overlays/Profile/Sections/CounterPill.cs index 34211b40b7..bd6cb4d09b 100644 --- a/osu.Game/Overlays/Profile/Sections/CounterPill.cs +++ b/osu.Game/Overlays/Profile/Sections/CounterPill.cs @@ -8,7 +8,7 @@ using osu.Game.Graphics; using osu.Framework.Bindables; using osu.Game.Graphics.Sprites; using osu.Framework.Allocation; -using osu.Framework.Localisation; +using osu.Framework.Extensions.LocalisationExtensions; namespace osu.Game.Overlays.Profile.Sections { diff --git a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs index 449b1da35d..a75235359a 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/ProfileLineChart.cs @@ -9,6 +9,7 @@ using System.Linq; using osu.Game.Graphics.Sprites; using osu.Framework.Utils; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Graphics; using osu.Framework.Graphics.Shapes; using osuTK; diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index ac94f0fc87..d25c53b5ec 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using static osu.Game.Users.User; diff --git a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs index eb55a0a78d..762716efab 100644 --- a/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs +++ b/osu.Game/Overlays/Profile/Sections/Kudosu/KudosuInfo.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Users; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Resources.Localisation.Web; using osu.Framework.Localisation; diff --git a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs index 4e4a665a60..f77464ecb9 100644 --- a/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs +++ b/osu.Game/Overlays/Profile/Sections/Ranks/DrawableProfileWeightedScore.cs @@ -1,9 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs index 5309778a47..0f071883ca 100644 --- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs +++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs @@ -16,6 +16,7 @@ using System.Collections.Generic; using osu.Framework.Graphics.UserInterface; using osu.Game.Online.API.Requests; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; diff --git a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs index 85a317728f..a908380e95 100644 --- a/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/CountriesTable.cs @@ -9,8 +9,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using System.Collections.Generic; using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Resources.Localisation.Web; -using osu.Framework.Localisation; namespace osu.Game.Overlays.Rankings.Tables { diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index 6facf1e7a2..215cc95198 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs index bc8eac16a9..6e6230f958 100644 --- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs @@ -10,6 +10,7 @@ using osu.Framework.Extensions; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Users; using osu.Game.Users.Drawables; using osuTK; diff --git a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs index b6bb66e2c8..934da4501e 100644 --- a/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/ScoresTable.cs @@ -2,9 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; using osu.Game.Users; diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs index b96ab556df..cc2ef55a2b 100644 --- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; diff --git a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs index 68e3f0df7d..d04e60a2ab 100644 --- a/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs +++ b/osu.Game/Screens/Play/HUD/MatchScoreDisplay.cs @@ -4,6 +4,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; diff --git a/osu.Game/Screens/Select/Details/UserRatings.cs b/osu.Game/Screens/Select/Details/UserRatings.cs index a7f28b932a..eabc476db9 100644 --- a/osu.Game/Screens/Select/Details/UserRatings.cs +++ b/osu.Game/Screens/Select/Details/UserRatings.cs @@ -8,8 +8,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using System.Linq; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Game.Beatmaps; -using osu.Framework.Localisation; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Screens.Select.Details diff --git a/osu.Game/Utils/FormatUtils.cs b/osu.Game/Utils/FormatUtils.cs index e763558647..d14dbb49f3 100644 --- a/osu.Game/Utils/FormatUtils.cs +++ b/osu.Game/Utils/FormatUtils.cs @@ -3,6 +3,7 @@ using System; using Humanizer; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Localisation; namespace osu.Game.Utils From 8f3416d8534405210acb21b939ef22c011e674c9 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 29 Aug 2021 16:03:37 +0300 Subject: [PATCH 679/961] Assert PP not null when `showPerformancePoints` is true --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index a154016824..8fe1d35b62 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions; @@ -192,6 +193,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (showPerformancePoints) { + Debug.Assert(score.PP != null); + content.Add(new OsuSpriteText { Text = score.PP.ToLocalisableString(@"N0"), From 6aaef7b0be3985b30f142f1e8562a744bd4373cc Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 29 Aug 2021 17:19:13 +0300 Subject: [PATCH 680/961] Handle null PP during score set in `TopScoreStatisticsSection` Supersedes #14562 Closes #14541 --- .../Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs index 23069eccdf..883e83ce6e 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs @@ -116,7 +116,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores maxComboColumn.Text = value.MaxCombo.ToLocalisableString(@"0\x"); ppColumn.Alpha = value.Beatmap?.Status.GrantsPerformancePoints() == true ? 1 : 0; - ppColumn.Text = value.PP.ToLocalisableString(@"N0"); + ppColumn.Text = value.PP?.ToLocalisableString(@"N0"); statisticsColumns.ChildrenEnumerable = value.GetStatisticsForDisplay().Select(createStatisticsColumn); modsColumn.Mods = value.Mods; From 6dc11543ad527683bb8691e609ec4e486191f138 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sun, 29 Aug 2021 17:20:33 +0300 Subject: [PATCH 681/961] Handle (null?) PP in `PerformanceTable` --- osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs index 215cc95198..17c17b1f1a 100644 --- a/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs +++ b/osu.Game/Overlays/Rankings/Tables/PerformanceTable.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Rankings.Tables protected override Drawable[] CreateUniqueContent(UserStatistics item) => new Drawable[] { - new RowText { Text = item.PP.ToLocalisableString(@"N0"), } + new RowText { Text = item.PP?.ToLocalisableString(@"N0"), } }; } } From 90c313e2ad4d67d827f5617feacba4b1a693fb12 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 29 Aug 2021 19:19:55 +0100 Subject: [PATCH 682/961] add methods to get a user from their username --- osu.Game/Online/API/Requests/GetUserRequest.cs | 16 +++++++++++++--- osu.Game/OsuGame.cs | 9 +++++++-- osu.Game/Overlays/UserProfileOverlay.cs | 4 +++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 42aad6f9eb..48041cd40c 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -8,15 +8,25 @@ namespace osu.Game.Online.API.Requests { public class GetUserRequest : APIRequest { - private readonly long? userId; + private readonly string userIdentifier; public readonly RulesetInfo Ruleset; + public GetUserRequest() + { + } + public GetUserRequest(long? userId = null, RulesetInfo ruleset = null) { - this.userId = userId; + this.userIdentifier = userId.ToString(); Ruleset = ruleset; } - protected override string Target => userId.HasValue ? $@"users/{userId}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; + public GetUserRequest(string username = null, RulesetInfo ruleset = null) + { + this.userIdentifier = username; + Ruleset = ruleset; + } + + protected override string Target => (userIdentifier != null) ? $@"users/{userIdentifier}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; } } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 4d952c39c6..26fa1d5a4c 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -329,8 +329,7 @@ namespace osu.Game break; case LinkAction.OpenUserProfile: - if (int.TryParse(link.Argument, out int userId)) - ShowUser(userId); + ShowUser(link.Argument); break; case LinkAction.OpenWiki: @@ -378,6 +377,12 @@ namespace osu.Game /// The user to display. public void ShowUser(int userId) => waitForReady(() => userProfile, _ => userProfile.ShowUser(userId)); + /// + /// Show a user's profile as an overlay. + /// + /// The user to display. + public void ShowUser(string username) => waitForReady(() => userProfile, _ => userProfile.ShowUser(username)); + /// /// Show a beatmap's set as an overlay, displaying the given beatmap. /// diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 299a14b250..6e74acc96a 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -40,6 +40,8 @@ namespace osu.Game.Overlays public void ShowUser(int userId) => ShowUser(new User { Id = userId }); + public void ShowUser(string username) => ShowUser(new User { Username = username }); + public void ShowUser(User user, bool fetchOnline = true) { if (user == User.SYSTEM_USER) @@ -116,7 +118,7 @@ namespace osu.Game.Overlays if (fetchOnline) { - userReq = new GetUserRequest(user.Id); + userReq = user.Username != null ? new GetUserRequest(user.Username) : new GetUserRequest(user.Id); userReq.Success += userLoadComplete; API.Queue(userReq); } From 7bb2269eba507366da5f6cc85c7cee48421ff8a2 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 29 Aug 2021 22:27:56 -0700 Subject: [PATCH 683/961] Add overlay closing behavior test --- .../Navigation/TestSceneScreenNavigation.cs | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index 3c65f46c79..a112534837 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -323,6 +323,69 @@ namespace osu.Game.Tests.Visual.Navigation AddWaitStep("wait two frames", 2); } + [Test] + public void TestOverlayClosing() + { + // use now playing overlay for "overlay -> background" drag case + // since most overlays use a scroll container that absorbs on mouse down + NowPlayingOverlay nowPlayingOverlay = null; + + AddStep("enter menu", () => InputManager.Key(Key.Enter)); + + AddStep("get and press now playing hotkey", () => + { + nowPlayingOverlay = Game.ChildrenOfType().Single(); + InputManager.Key(Key.F6); + }); + + // drag tests + + // background -> toolbar + AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight)); + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddStep("move cursor to toolbar", () => InputManager.MoveMouseTo(Game.Toolbar.ScreenSpaceDrawQuad.Centre)); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + + // toolbar -> background + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight)); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + + // background -> overlay + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddStep("move cursor to now playing overlay", () => InputManager.MoveMouseTo(nowPlayingOverlay.ScreenSpaceDrawQuad.Centre)); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + + // overlay -> background + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight)); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + + // background -> background + AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); + AddStep("move cursor to left", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomLeft)); + AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); + AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden); + + AddStep("press now playing hotkey", () => InputManager.Key(Key.F6)); + + // click tests + + // toolbar + AddStep("move cursor to toolbar", () => InputManager.MoveMouseTo(Game.Toolbar.ScreenSpaceDrawQuad.Centre)); + AddStep("click left mouse button", () => InputManager.Click(MouseButton.Left)); + AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + + // background + AddStep("move cursor to background", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.BottomRight)); + AddStep("click left mouse button", () => InputManager.Click(MouseButton.Left)); + AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden); + } + private void pushEscape() => AddStep("Press escape", () => InputManager.Key(Key.Escape)); From ee49305cad0f0edc6c7a7c0b5c65d8d63b95a3b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 14:40:25 +0900 Subject: [PATCH 684/961] Move taiko legacy speed multiplier to `osu.Game` project Allows it to be used in local case in `LegacyBeatmapEncoder`. --- .../Beatmaps/TaikoBeatmapConverter.cs | 10 ++-------- osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs | 4 ++-- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 8 +++++++- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 90c99316b1..77f058fad9 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -18,12 +18,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps { internal class TaikoBeatmapConverter : BeatmapConverter { - /// - /// osu! is generally slower than taiko, so a factor is added to increase - /// speed. This must be used everywhere slider length or beat length is used. - /// - public const float LEGACY_VELOCITY_MULTIPLIER = 1.4f; - /// /// Because swells are easier in taiko than spinners are in osu!, /// legacy taiko multiplies a factor when converting the number of required hits. @@ -55,7 +49,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps // Rewrite the beatmap info to add the slider velocity multiplier original.BeatmapInfo = original.BeatmapInfo.Clone(); original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone(); - original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LEGACY_VELOCITY_MULTIPLIER; + original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; Beatmap converted = base.ConvertBeatmap(original, cancellationToken); @@ -155,7 +149,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps // The true distance, accounting for any repeats. This ends up being the drum roll distance later int spans = (obj as IHasRepeats)?.SpanCount() ?? 1; - double distance = distanceData.Distance * spans * LEGACY_VELOCITY_MULTIPLIER; + double distance = distanceData.Distance * spans * LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; TimingControlPoint timingPoint = beatmap.ControlPointInfo.TimingPointAt(obj.StartTime); DifficultyControlPoint difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(obj.StartTime); diff --git a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs index c0377c67a5..b0634295d0 100644 --- a/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs +++ b/osu.Game.Rulesets.Taiko/Objects/DrumRoll.cs @@ -6,10 +6,10 @@ using System; using System.Threading; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Formats; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Scoring; -using osu.Game.Rulesets.Taiko.Beatmaps; using osu.Game.Rulesets.Taiko.Judgements; using osuTK; @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Taiko.Objects double IHasDistance.Distance => Duration * Velocity; SliderPath IHasPath.Path - => new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER); + => new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(1) }, ((IHasDistance)this).Distance / LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER); #endregion } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 246dc991d5..1595ba5b8e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -24,6 +24,12 @@ namespace osu.Game.Beatmaps.Formats { public const int LATEST_VERSION = 128; + /// + /// osu! is generally slower than taiko, so a factor is added to increase + /// speed. This must be used everywhere slider length or beat length is used. + /// + public const float LEGACY_TAIKO_VELOCITY_MULTIPLIER = 1.4f; + private readonly IBeatmap beatmap; [CanBeNull] @@ -142,7 +148,7 @@ namespace osu.Game.Beatmaps.Formats // Taiko adjusts the slider multiplier (see: TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER) writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1 - ? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / 1.4f}") + ? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}") : FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}")); writer.WriteLine(FormattableString.Invariant($"SliderTickRate: {beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate}")); From 4adfe9a6dc3a4b05d67c4c626f2e7b2009d9b785 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 15:30:04 +0900 Subject: [PATCH 685/961] Add test coverage of double-convert stability --- .../Beatmaps/Formats/LegacyBeatmapEncoderTest.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 855a75117d..96986f06d5 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -49,6 +49,22 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); } + [TestCaseSource(nameof(allBeatmaps))] + public void TestEncodeDecodeStabilityDoubleConvert(string name) + { + var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name); + var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name); + + // run an extra convert. this is expected to be stable. + decodedAfterEncode.beatmap = convert(decodedAfterEncode.beatmap); + + sort(decoded.beatmap); + sort(decodedAfterEncode.beatmap); + + Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(decoded.beatmap.Serialize())); + Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); + } + [Test] public void TestEncodeMultiSegmentSliderWithFloatingPointError() { From 6a6dac609caaad6e60d94a49224efb532e1111eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 15:30:17 +0900 Subject: [PATCH 686/961] Fix instability of taiko double conversion Until now, the taiko speed multiplier was potentially applied more than once if conversion was run multiple times. --- .../Beatmaps/TaikoBeatmapConverter.cs | 19 +++++++++++++++---- osu.Game/Beatmaps/BeatmapDifficulty.cs | 18 +++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs index 77f058fad9..9b73e644c5 100644 --- a/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs +++ b/osu.Game.Rulesets.Taiko/Beatmaps/TaikoBeatmapConverter.cs @@ -46,10 +46,12 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps protected override Beatmap ConvertBeatmap(IBeatmap original, CancellationToken cancellationToken) { - // Rewrite the beatmap info to add the slider velocity multiplier - original.BeatmapInfo = original.BeatmapInfo.Clone(); - original.BeatmapInfo.BaseDifficulty = original.BeatmapInfo.BaseDifficulty.Clone(); - original.BeatmapInfo.BaseDifficulty.SliderMultiplier *= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; + if (!(original.BeatmapInfo.BaseDifficulty is TaikoMutliplierAppliedDifficulty)) + { + // Rewrite the beatmap info to add the slider velocity multiplier + original.BeatmapInfo = original.BeatmapInfo.Clone(); + original.BeatmapInfo.BaseDifficulty = new TaikoMutliplierAppliedDifficulty(original.BeatmapInfo.BaseDifficulty); + } Beatmap converted = base.ConvertBeatmap(original, cancellationToken); @@ -188,5 +190,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps } protected override Beatmap CreateBeatmap() => new TaikoBeatmap(); + + private class TaikoMutliplierAppliedDifficulty : BeatmapDifficulty + { + public TaikoMutliplierAppliedDifficulty(BeatmapDifficulty difficulty) + { + difficulty.CopyTo(this); + SliderMultiplier *= LegacyBeatmapEncoder.LEGACY_TAIKO_VELOCITY_MULTIPLIER; + } + } } } diff --git a/osu.Game/Beatmaps/BeatmapDifficulty.cs b/osu.Game/Beatmaps/BeatmapDifficulty.cs index c56fec67aa..1844b193f2 100644 --- a/osu.Game/Beatmaps/BeatmapDifficulty.cs +++ b/osu.Game/Beatmaps/BeatmapDifficulty.cs @@ -32,7 +32,23 @@ namespace osu.Game.Beatmaps /// /// Returns a shallow-clone of this . /// - public BeatmapDifficulty Clone() => (BeatmapDifficulty)MemberwiseClone(); + public BeatmapDifficulty Clone() + { + var diff = new BeatmapDifficulty(); + CopyTo(diff); + return diff; + } + + public void CopyTo(BeatmapDifficulty difficulty) + { + difficulty.ApproachRate = ApproachRate; + difficulty.DrainRate = DrainRate; + difficulty.CircleSize = CircleSize; + difficulty.OverallDifficulty = OverallDifficulty; + + difficulty.SliderMultiplier = SliderMultiplier; + difficulty.SliderTickRate = SliderTickRate; + } /// /// Maps a difficulty value [0, 10] to a two-piece linear range of values. From 58a052ea1f7bf15a980870d48b7176b9e5c026d8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:00:07 +0900 Subject: [PATCH 687/961] 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 f18400bf2f..8a9bf1b9cd 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a89d57cd1f..b4d4aa3070 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index bb4700a081..29e9b9fe20 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From fa2bf421886fe70c14706ae2d41831afcf7e49fb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:04:54 +0900 Subject: [PATCH 688/961] Update tooltip implementations --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 6 ++---- .../Graphics/Cursor/OsuTooltipContainer.cs | 9 ++------- osu.Game/Graphics/DateTooltip.cs | 8 ++------ osu.Game/Overlays/Mods/ModButtonTooltip.cs | 19 ++++--------------- .../Profile/Header/Components/RankGraph.cs | 5 ++--- .../Sections/Historical/UserHistoryGraph.cs | 5 ++--- osu.Game/Overlays/Profile/UserGraph.cs | 2 +- 7 files changed, 15 insertions(+), 39 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 3210ef0112..199f719893 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -259,10 +259,10 @@ namespace osu.Game.Beatmaps.Drawables private readonly IBindable starDifficulty = new Bindable(); - public bool SetContent(object content) + public void SetContent(object content) { if (!(content is DifficultyIconTooltipContent iconContent)) - return false; + return; difficultyName.Text = iconContent.Beatmap.Version; @@ -273,8 +273,6 @@ namespace osu.Game.Beatmaps.Drawables starRating.Text = $"{difficulty.NewValue.Stars:0.##}"; difficultyFlow.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars); }, true); - - return true; } public void Move(Vector2 pos) => Position = pos; diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs index 81dca99ddd..35d7b4e795 100644 --- a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs @@ -31,12 +31,9 @@ namespace osu.Game.Graphics.Cursor private readonly OsuSpriteText text; private bool instantMovement = true; - public override bool SetContent(object content) + public override void SetContent(LocalisableString contentString) { - if (!(content is LocalisableString contentString)) - return false; - - if (contentString == text.Text) return true; + if (contentString == text.Text) return; text.Text = contentString; @@ -47,8 +44,6 @@ namespace osu.Game.Graphics.Cursor } else AutoSizeDuration = 0; - - return true; } public OsuTooltip() diff --git a/osu.Game/Graphics/DateTooltip.cs b/osu.Game/Graphics/DateTooltip.cs index 67fcab43f7..3094f9cc2b 100644 --- a/osu.Game/Graphics/DateTooltip.cs +++ b/osu.Game/Graphics/DateTooltip.cs @@ -12,7 +12,7 @@ using osuTK; namespace osu.Game.Graphics { - public class DateTooltip : VisibilityContainer, ITooltip + public class DateTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText dateText, timeText; private readonly Box background; @@ -63,14 +63,10 @@ namespace osu.Game.Graphics protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); - public bool SetContent(object content) + public void SetContent(DateTimeOffset date) { - if (!(content is DateTimeOffset date)) - return false; - dateText.Text = $"{date:d MMMM yyyy} "; timeText.Text = $"{date:HH:mm:ss \"UTC\"z}"; - return true; } public void Move(Vector2 pos) => Position = pos; diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 666ed07e28..89fcd61d76 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.cs @@ -18,7 +18,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModButtonTooltip : VisibilityContainer, ITooltip + public class ModButtonTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText descriptionText; private readonly Box background; @@ -82,12 +82,9 @@ namespace osu.Game.Overlays.Mods private Mod lastMod; - public bool SetContent(object content) + public void SetContent(Mod mod) { - if (!(content is Mod mod)) - return false; - - if (mod.Equals(lastMod)) return true; + if (mod.Equals(lastMod)) return; lastMod = mod; @@ -99,15 +96,7 @@ namespace osu.Game.Overlays.Mods incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); - if (!incompatibleMods.Value.Any()) - { - incompatibleText.Text = "Compatible with all mods"; - return true; - } - - incompatibleText.Text = "Incompatible with:"; - - return true; + incompatibleText.Text = !incompatibleMods.Value.Any() ? "Compatible with all mods" : "Incompatible with:"; } public void Move(Vector2 pos) => Position = pos; diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index e8bce404e1..7ba8ae7c80 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -81,14 +81,13 @@ namespace osu.Game.Overlays.Profile.Header.Components { } - public override bool SetContent(object content) + public override void SetContent(object content) { if (!(content is TooltipDisplayContent info)) - return false; + return; Counter.Text = info.Rank; BottomText.Text = info.Time; - return true; } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index d25c53b5ec..85287d2325 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -50,14 +50,13 @@ namespace osu.Game.Overlays.Profile.Sections.Historical this.tooltipCounterName = tooltipCounterName; } - public override bool SetContent(object content) + public override void SetContent(object content) { if (!(content is TooltipDisplayContent info) || info.Name != tooltipCounterName) - return false; + return; Counter.Text = info.Count; BottomText.Text = info.Date; - return true; } } diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index b7a08b6c5e..b88cc32ff7 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -268,7 +268,7 @@ namespace osu.Game.Overlays.Profile background.Colour = colours.Gray1; } - public abstract bool SetContent(object content); + public abstract void SetContent(object content); private bool instantMove = true; From 678386f5c4672bda1c762ccbe26673259808e928 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:05:56 +0900 Subject: [PATCH 689/961] Fix missed null coalesce --- 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 7704fa24df..5c3906cb39 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreUserSection.cs @@ -128,7 +128,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public int? ScorePosition { - set => rankText.Text = value == null ? (LocalisableString)"-" : value.ToLocalisableString(@"\##"); + set => rankText.Text = value?.ToLocalisableString(@"\##") ?? (LocalisableString)"-"; } /// From da7a871afa1edc784fe111e4f500baaa9d1f740e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:27:24 +0900 Subject: [PATCH 690/961] Update inline comment to point to new variable location Co-authored-by: PercyDan <50285552+PercyDan54@users.noreply.github.com> --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 1595ba5b8e..fb6806a13d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -146,7 +146,7 @@ namespace osu.Game.Beatmaps.Formats writer.WriteLine(FormattableString.Invariant($"OverallDifficulty: {beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty}")); writer.WriteLine(FormattableString.Invariant($"ApproachRate: {beatmap.BeatmapInfo.BaseDifficulty.ApproachRate}")); - // Taiko adjusts the slider multiplier (see: TaikoBeatmapConverter.LEGACY_VELOCITY_MULTIPLIER) + // Taiko adjusts the slider multiplier (see: LEGACY_TAIKO_VELOCITY_MULTIPLIER) writer.WriteLine(beatmap.BeatmapInfo.RulesetID == 1 ? FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier / LEGACY_TAIKO_VELOCITY_MULTIPLIER}") : FormattableString.Invariant($"SliderMultiplier: {beatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier}")); From 7257aae7f26bd4c322d04e5aa739207773c5bfbd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 Aug 2021 18:00:57 +0900 Subject: [PATCH 691/961] Move samples to `LegacyControlPointInfo` --- .../Formats/LegacyBeatmapDecoderTest.cs | 5 +- .../NonVisual/ControlPointInfoTest.cs | 4 +- .../ControlPoints/ControlPointInfo.cs | 119 +++++++++++------- .../Beatmaps/Formats/LegacyBeatmapDecoder.cs | 22 ++++ .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 4 +- osu.Game/Rulesets/Objects/HitObject.cs | 7 +- osu.Game/Screens/Edit/Timing/SampleSection.cs | 12 +- 7 files changed, 110 insertions(+), 63 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 12633ee8c9..24410c886f 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -10,6 +10,7 @@ using osu.Game.Tests.Resources; using System.Linq; using osu.Game.Audio; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.Timing; @@ -166,7 +167,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var stream = new LineBufferedReader(resStream)) { var beatmap = decoder.Decode(stream); - var controlPoints = beatmap.ControlPointInfo; + var controlPoints = (LegacyControlPointInfo)beatmap.ControlPointInfo; Assert.AreEqual(4, controlPoints.TimingPoints.Count); Assert.AreEqual(5, controlPoints.DifficultyPoints.Count); @@ -240,7 +241,7 @@ namespace osu.Game.Tests.Beatmaps.Formats using (var resStream = TestResources.OpenResource("overlapping-control-points.osu")) using (var stream = new LineBufferedReader(resStream)) { - var controlPoints = decoder.Decode(stream).ControlPointInfo; + var controlPoints = (LegacyControlPointInfo)decoder.Decode(stream).ControlPointInfo; Assert.That(controlPoints.TimingPoints.Count, Is.EqualTo(4)); Assert.That(controlPoints.DifficultyPoints.Count, Is.EqualTo(3)); diff --git a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs index 240ae4a90c..e1d6df814e 100644 --- a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs +++ b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs @@ -64,7 +64,7 @@ namespace osu.Game.Tests.NonVisual [Test] public void TestAddRedundantSample() { - var cpi = new ControlPointInfo(); + var cpi = new LegacyControlPointInfo(); cpi.Add(0, new SampleControlPoint()); // is *not* redundant, special exception for first sample point cpi.Add(1000, new SampleControlPoint()); // is redundant @@ -142,7 +142,7 @@ namespace osu.Game.Tests.NonVisual [Test] public void TestRemoveGroupAlsoRemovedControlPoints() { - var cpi = new ControlPointInfo(); + var cpi = new LegacyControlPointInfo(); var group = cpi.GroupAt(1000, true); diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 2d0fc17a7b..7cc4fa6dc4 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -14,6 +14,64 @@ using osu.Game.Utils; namespace osu.Game.Beatmaps.ControlPoints { + public class LegacyControlPointInfo : ControlPointInfo + { + /// + /// All sound points. + /// + [JsonProperty] + public IBindableList SamplePoints => samplePoints; + + private readonly BindableList samplePoints = new BindableList(); + + /// + /// Finds the sound control point that is active at . + /// + /// The time to find the sound control point at. + /// The sound control point. + [NotNull] + public SampleControlPoint SamplePointAt(double time) => BinarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT); + + public override void Clear() + { + base.Clear(); + samplePoints.Clear(); + } + + protected override bool CheckAlreadyExisting(double time, ControlPoint newPoint) + { + if (newPoint is SampleControlPoint _) + { + var existing = BinarySearch(SamplePoints, time); + return newPoint?.IsRedundant(existing) == true; + } + + return base.CheckAlreadyExisting(time, newPoint); + } + + protected override void GroupItemAdded(ControlPoint controlPoint) + { + if (controlPoint is SampleControlPoint typed) + { + samplePoints.Add(typed); + return; + } + + base.GroupItemAdded(controlPoint); + } + + protected override void GroupItemRemoved(ControlPoint controlPoint) + { + if (controlPoint is SampleControlPoint typed) + { + samplePoints.Remove(typed); + return; + } + + base.GroupItemRemoved(controlPoint); + } + } + [Serializable] public class ControlPointInfo : IDeepCloneable { @@ -41,14 +99,6 @@ namespace osu.Game.Beatmaps.ControlPoints private readonly SortedList difficultyPoints = new SortedList(Comparer.Default); - /// - /// All sound points. - /// - [JsonProperty] - public IBindableList SamplePoints => samplePoints; - - private readonly BindableList samplePoints = new BindableList(); - /// /// All effect points. /// @@ -69,7 +119,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the difficulty control point at. /// The difficulty control point. [NotNull] - public DifficultyControlPoint DifficultyPointAt(double time) => binarySearchWithFallback(DifficultyPoints, time, DifficultyControlPoint.DEFAULT); + public DifficultyControlPoint DifficultyPointAt(double time) => BinarySearchWithFallback(DifficultyPoints, time, DifficultyControlPoint.DEFAULT); /// /// Finds the effect control point that is active at . @@ -77,15 +127,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the effect control point at. /// The effect control point. [NotNull] - public EffectControlPoint EffectPointAt(double time) => binarySearchWithFallback(EffectPoints, time, EffectControlPoint.DEFAULT); - - /// - /// Finds the sound control point that is active at . - /// - /// The time to find the sound control point at. - /// The sound control point. - [NotNull] - public SampleControlPoint SamplePointAt(double time) => binarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT); + public EffectControlPoint EffectPointAt(double time) => BinarySearchWithFallback(EffectPoints, time, EffectControlPoint.DEFAULT); /// /// Finds the timing control point that is active at . @@ -93,7 +135,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the timing control point at. /// The timing control point. [NotNull] - public TimingControlPoint TimingPointAt(double time) => binarySearchWithFallback(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : TimingControlPoint.DEFAULT); + public TimingControlPoint TimingPointAt(double time) => BinarySearchWithFallback(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : TimingControlPoint.DEFAULT); /// /// Finds the maximum BPM represented by any timing control point. @@ -112,12 +154,11 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// Remove all s and return to a pristine state. /// - public void Clear() + public virtual void Clear() { groups.Clear(); timingPoints.Clear(); difficultyPoints.Clear(); - samplePoints.Clear(); effectPoints.Clear(); } @@ -129,7 +170,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// Whether the control point was added. public bool Add(double time, ControlPoint controlPoint) { - if (checkAlreadyExisting(time, controlPoint)) + if (CheckAlreadyExisting(time, controlPoint)) return false; GroupAt(time, true).Add(controlPoint); @@ -147,8 +188,8 @@ namespace osu.Game.Beatmaps.ControlPoints if (addIfNotExisting) { - newGroup.ItemAdded += groupItemAdded; - newGroup.ItemRemoved += groupItemRemoved; + newGroup.ItemAdded += GroupItemAdded; + newGroup.ItemRemoved += GroupItemRemoved; groups.Insert(~i, newGroup); return newGroup; @@ -162,8 +203,8 @@ namespace osu.Game.Beatmaps.ControlPoints foreach (var item in group.ControlPoints.ToArray()) group.Remove(item); - group.ItemAdded -= groupItemAdded; - group.ItemRemoved -= groupItemRemoved; + group.ItemAdded -= GroupItemAdded; + group.ItemRemoved -= GroupItemRemoved; groups.Remove(group); } @@ -228,10 +269,10 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the control point at. /// The control point to use when is before any control points. /// The active control point at , or a fallback if none found. - private T binarySearchWithFallback(IReadOnlyList list, double time, T fallback) + protected T BinarySearchWithFallback(IReadOnlyList list, double time, T fallback) where T : ControlPoint { - return binarySearch(list, time) ?? fallback; + return BinarySearch(list, time) ?? fallback; } /// @@ -240,7 +281,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The list to search. /// The time to find the control point at. /// The active control point at . - private T binarySearch(IReadOnlyList list, double time) + protected virtual T BinarySearch(IReadOnlyList list, double time) where T : ControlPoint { if (list == null) @@ -280,7 +321,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// The time to find the timing control point at. /// A point to be added. /// Whether the new point should be added. - private bool checkAlreadyExisting(double time, ControlPoint newPoint) + protected virtual bool CheckAlreadyExisting(double time, ControlPoint newPoint) { ControlPoint existing = null; @@ -288,17 +329,13 @@ namespace osu.Game.Beatmaps.ControlPoints { case TimingControlPoint _: // Timing points are a special case and need to be added regardless of fallback availability. - existing = binarySearch(TimingPoints, time); + existing = BinarySearch(TimingPoints, time); break; case EffectControlPoint _: existing = EffectPointAt(time); break; - case SampleControlPoint _: - existing = binarySearch(SamplePoints, time); - break; - case DifficultyControlPoint _: existing = DifficultyPointAt(time); break; @@ -307,7 +344,7 @@ namespace osu.Game.Beatmaps.ControlPoints return newPoint?.IsRedundant(existing) == true; } - private void groupItemAdded(ControlPoint controlPoint) + protected virtual void GroupItemAdded(ControlPoint controlPoint) { switch (controlPoint) { @@ -319,17 +356,13 @@ namespace osu.Game.Beatmaps.ControlPoints effectPoints.Add(typed); break; - case SampleControlPoint typed: - samplePoints.Add(typed); - break; - case DifficultyControlPoint typed: difficultyPoints.Add(typed); break; } } - private void groupItemRemoved(ControlPoint controlPoint) + protected virtual void GroupItemRemoved(ControlPoint controlPoint) { switch (controlPoint) { @@ -341,10 +374,6 @@ namespace osu.Game.Beatmaps.ControlPoints effectPoints.Remove(typed); break; - case SampleControlPoint typed: - samplePoints.Remove(typed); - break; - case DifficultyControlPoint typed: difficultyPoints.Remove(typed); break; diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 0ddc9e4c48..9bd76a9f2c 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -44,6 +44,13 @@ namespace osu.Game.Beatmaps.Formats offset = FormatVersion < 5 ? 24 : 0; } + protected override Beatmap CreateTemplateObject() + { + var templateBeatmap = base.CreateTemplateObject(); + templateBeatmap.ControlPointInfo = new LegacyControlPointInfo(); + return templateBeatmap; + } + protected override void ParseStreamInto(LineBufferedReader stream, Beatmap beatmap) { this.beatmap = beatmap; @@ -394,8 +401,16 @@ namespace osu.Game.Beatmaps.Formats private readonly HashSet pendingControlPointTypes = new HashSet(); private double pendingControlPointsTime; + private readonly LegacyControlPointInfo controlPointInfo = new LegacyControlPointInfo(); + private void addControlPoint(double time, ControlPoint point, bool timingChange) { + if (point is SampleControlPoint) + { + controlPointInfo.Add(time, point); + return; + } + if (time != pendingControlPointsTime) flushPendingPoints(); @@ -430,8 +445,15 @@ namespace osu.Game.Beatmaps.Formats parser ??= new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(getOffsetTime(), FormatVersion); var obj = parser.Parse(line); + if (obj != null) + { + // assign legacy control points directly to hitobject + //obj.SampleControlPoint = controlPointInfo.SamplePointAt(obj.StartTime); + obj.ApplyDefaults(controlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + beatmap.HitObjects.Add(obj); + } } private int getOffsetTime(int time) => time + (ApplyOffsets ? offset : 0); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 246dc991d5..a6c41a3cf6 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -80,7 +80,7 @@ namespace osu.Game.Beatmaps.Formats writer.WriteLine(FormattableString.Invariant($"AudioLeadIn: {beatmap.BeatmapInfo.AudioLeadIn}")); writer.WriteLine(FormattableString.Invariant($"PreviewTime: {beatmap.Metadata.PreviewTime}")); writer.WriteLine(FormattableString.Invariant($"Countdown: {(int)beatmap.BeatmapInfo.Countdown}")); - writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank(beatmap.ControlPointInfo.SamplePointAt(double.MinValue).SampleBank)}")); + writer.WriteLine(FormattableString.Invariant($"SampleSet: {toLegacySampleBank((beatmap.HitObjects.FirstOrDefault()?.SampleControlPoint ?? SampleControlPoint.DEFAULT).SampleBank)}")); writer.WriteLine(FormattableString.Invariant($"StackLeniency: {beatmap.BeatmapInfo.StackLeniency}")); writer.WriteLine(FormattableString.Invariant($"Mode: {beatmap.BeatmapInfo.RulesetID}")); writer.WriteLine(FormattableString.Invariant($"LetterboxInBreaks: {(beatmap.BeatmapInfo.LetterboxInBreaks ? '1' : '0')}")); @@ -187,7 +187,7 @@ namespace osu.Game.Beatmaps.Formats void outputControlPointEffectsAt(double time, bool isTimingPoint) { - var samplePoint = beatmap.ControlPointInfo.SamplePointAt(time); + var samplePoint = ((LegacyControlPointInfo)beatmap.ControlPointInfo).SamplePointAt(time); var effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); // Apply the control point to a hit sample to uncover legacy properties (e.g. suffix) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 422655502d..fd9f02604c 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -106,8 +106,11 @@ namespace osu.Game.Rulesets.Objects { ApplyDefaultsToSelf(controlPointInfo, difficulty); - // This is done here since ApplyDefaultsToSelf may be used to determine the end time - SampleControlPoint = controlPointInfo.SamplePointAt(this.GetEndTime() + control_point_leniency); + if (controlPointInfo is LegacyControlPointInfo legacyInfo) + { + // This is done here since ApplyDefaultsToSelf may be used to determine the end time + SampleControlPoint = legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency); + } nestedHitObjects.Clear(); diff --git a/osu.Game/Screens/Edit/Timing/SampleSection.cs b/osu.Game/Screens/Edit/Timing/SampleSection.cs index cc73af6349..be8de18502 100644 --- a/osu.Game/Screens/Edit/Timing/SampleSection.cs +++ b/osu.Game/Screens/Edit/Timing/SampleSection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -42,15 +43,6 @@ namespace osu.Game.Screens.Edit.Timing } } - protected override SampleControlPoint CreatePoint() - { - var reference = Beatmap.ControlPointInfo.SamplePointAt(SelectedGroup.Value.Time); - - return new SampleControlPoint - { - SampleBank = reference.SampleBank, - SampleVolume = reference.SampleVolume, - }; - } + protected override SampleControlPoint CreatePoint() => new SampleControlPoint(); // TODO: remove } } From ccacf56dd843352743d589adfe98c6c0c48a54db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 14:12:30 +0900 Subject: [PATCH 692/961] Move to legacy namespace --- .../Formats/LegacyBeatmapDecoderTest.cs | 12 ++-- .../NonVisual/ControlPointInfoTest.cs | 1 + .../ControlPoints/ControlPointInfo.cs | 58 ---------------- .../Beatmaps/Legacy/LegacyControlPointInfo.cs | 68 +++++++++++++++++++ osu.Game/Rulesets/Objects/HitObject.cs | 1 + osu.Game/Screens/Edit/Timing/SampleSection.cs | 1 - 6 files changed, 76 insertions(+), 65 deletions(-) create mode 100644 osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 24410c886f..8560a36fb4 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -3,16 +3,12 @@ using System; using System.IO; -using NUnit.Framework; -using osuTK; -using osuTK.Graphics; -using osu.Game.Tests.Resources; using System.Linq; +using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; -using osu.Game.Beatmaps.ControlPoints; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Beatmaps.Formats; +using osu.Game.Beatmaps.Legacy; using osu.Game.Beatmaps.Timing; using osu.Game.IO; using osu.Game.Rulesets.Catch; @@ -20,9 +16,13 @@ using osu.Game.Rulesets.Catch.Beatmaps; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Legacy; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Skinning; +using osu.Game.Tests.Resources; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Tests.Beatmaps.Formats { diff --git a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs index e1d6df814e..fabb016d5f 100644 --- a/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs +++ b/osu.Game.Tests/NonVisual/ControlPointInfoTest.cs @@ -4,6 +4,7 @@ using System.Linq; using NUnit.Framework; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Legacy; namespace osu.Game.Tests.NonVisual { diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 7cc4fa6dc4..d2a3b2fc8b 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -14,64 +14,6 @@ using osu.Game.Utils; namespace osu.Game.Beatmaps.ControlPoints { - public class LegacyControlPointInfo : ControlPointInfo - { - /// - /// All sound points. - /// - [JsonProperty] - public IBindableList SamplePoints => samplePoints; - - private readonly BindableList samplePoints = new BindableList(); - - /// - /// Finds the sound control point that is active at . - /// - /// The time to find the sound control point at. - /// The sound control point. - [NotNull] - public SampleControlPoint SamplePointAt(double time) => BinarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT); - - public override void Clear() - { - base.Clear(); - samplePoints.Clear(); - } - - protected override bool CheckAlreadyExisting(double time, ControlPoint newPoint) - { - if (newPoint is SampleControlPoint _) - { - var existing = BinarySearch(SamplePoints, time); - return newPoint?.IsRedundant(existing) == true; - } - - return base.CheckAlreadyExisting(time, newPoint); - } - - protected override void GroupItemAdded(ControlPoint controlPoint) - { - if (controlPoint is SampleControlPoint typed) - { - samplePoints.Add(typed); - return; - } - - base.GroupItemAdded(controlPoint); - } - - protected override void GroupItemRemoved(ControlPoint controlPoint) - { - if (controlPoint is SampleControlPoint typed) - { - samplePoints.Remove(typed); - return; - } - - base.GroupItemRemoved(controlPoint); - } - } - [Serializable] public class ControlPointInfo : IDeepCloneable { diff --git a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs new file mode 100644 index 0000000000..db9ff27f73 --- /dev/null +++ b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs @@ -0,0 +1,68 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using Newtonsoft.Json; +using osu.Framework.Bindables; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Beatmaps.Legacy +{ + public class LegacyControlPointInfo : ControlPointInfo + { + /// + /// All sound points. + /// + [JsonProperty] + public IBindableList SamplePoints => samplePoints; + + private readonly BindableList samplePoints = new BindableList(); + + /// + /// Finds the sound control point that is active at . + /// + /// The time to find the sound control point at. + /// The sound control point. + [NotNull] + public SampleControlPoint SamplePointAt(double time) => BinarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT); + + public override void Clear() + { + base.Clear(); + samplePoints.Clear(); + } + + protected override bool CheckAlreadyExisting(double time, ControlPoint newPoint) + { + if (newPoint is SampleControlPoint _) + { + var existing = BinarySearch(SamplePoints, time); + return newPoint?.IsRedundant(existing) == true; + } + + return base.CheckAlreadyExisting(time, newPoint); + } + + protected override void GroupItemAdded(ControlPoint controlPoint) + { + if (controlPoint is SampleControlPoint typed) + { + samplePoints.Add(typed); + return; + } + + base.GroupItemAdded(controlPoint); + } + + protected override void GroupItemRemoved(ControlPoint controlPoint) + { + if (controlPoint is SampleControlPoint typed) + { + samplePoints.Remove(typed); + return; + } + + base.GroupItemRemoved(controlPoint); + } + } +} diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index fd9f02604c..3e95659243 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -11,6 +11,7 @@ using osu.Framework.Bindables; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Scoring; diff --git a/osu.Game/Screens/Edit/Timing/SampleSection.cs b/osu.Game/Screens/Edit/Timing/SampleSection.cs index be8de18502..52709a2bbe 100644 --- a/osu.Game/Screens/Edit/Timing/SampleSection.cs +++ b/osu.Game/Screens/Edit/Timing/SampleSection.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; From 6fd24a5d92b933d45a78378ed509e6e444f24561 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 15:17:20 +0900 Subject: [PATCH 693/961] Remove redundant null coalesce --- osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs index db9ff27f73..fdfc22700a 100644 --- a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs +++ b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs @@ -37,7 +37,7 @@ namespace osu.Game.Beatmaps.Legacy if (newPoint is SampleControlPoint _) { var existing = BinarySearch(SamplePoints, time); - return newPoint?.IsRedundant(existing) == true; + return newPoint.IsRedundant(existing); } return base.CheckAlreadyExisting(time, newPoint); From 6ee4a6526caf053c236984e0eb383576aabbefd7 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:58:03 +0900 Subject: [PATCH 694/961] Don't block sample points from still being added to `ControlPointInfo` --- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 9bd76a9f2c..ec08c4a3f3 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -408,7 +408,6 @@ namespace osu.Game.Beatmaps.Formats if (point is SampleControlPoint) { controlPointInfo.Add(time, point); - return; } if (time != pendingControlPointsTime) From d35c4da90658b0fb7361e120dd3a001b2da7be04 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:58:21 +0900 Subject: [PATCH 695/961] Add new control point to legacy regeneration logic --- .../Beatmaps/Formats/LegacyBeatmapEncoder.cs | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index a6c41a3cf6..574af848d0 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -166,6 +166,30 @@ namespace osu.Game.Beatmaps.Formats writer.WriteLine("[TimingPoints]"); + if (!(beatmap.ControlPointInfo is LegacyControlPointInfo)) // todo: always run this? probably no harm. + { + var legacyControlPoints = new LegacyControlPointInfo(); + + foreach (var point in beatmap.ControlPointInfo.AllControlPoints) + legacyControlPoints.Add(point.Time, point.DeepClone()); + + beatmap.ControlPointInfo = legacyControlPoints; + + SampleControlPoint lastRelevantSamplePoint = null; + + // iterate over hitobjects and pull out all required sample changes + foreach (var h in beatmap.HitObjects) + { + var hSamplePoint = h.SampleControlPoint; + + if (!hSamplePoint.IsRedundant(lastRelevantSamplePoint)) + { + legacyControlPoints.Add(hSamplePoint.Time, hSamplePoint); + lastRelevantSamplePoint = hSamplePoint; + } + } + } + foreach (var group in beatmap.ControlPointInfo.Groups) { var groupTimingPoint = group.ControlPoints.OfType().FirstOrDefault(); @@ -175,17 +199,17 @@ namespace osu.Game.Beatmaps.Formats { writer.Write(FormattableString.Invariant($"{groupTimingPoint.Time},")); writer.Write(FormattableString.Invariant($"{groupTimingPoint.BeatLength},")); - outputControlPointEffectsAt(groupTimingPoint.Time, true); + outputControlPointAt(groupTimingPoint.Time, true); } // Output any remaining effects as secondary non-timing control point. var difficultyPoint = beatmap.ControlPointInfo.DifficultyPointAt(group.Time); writer.Write(FormattableString.Invariant($"{group.Time},")); writer.Write(FormattableString.Invariant($"{-100 / difficultyPoint.SpeedMultiplier},")); - outputControlPointEffectsAt(group.Time, false); + outputControlPointAt(group.Time, false); } - void outputControlPointEffectsAt(double time, bool isTimingPoint) + void outputControlPointAt(double time, bool isTimingPoint) { var samplePoint = ((LegacyControlPointInfo)beatmap.ControlPointInfo).SamplePointAt(time); var effectPoint = beatmap.ControlPointInfo.EffectPointAt(time); From 2115d6f93e8d2bf844ca1f69c85f7658167663a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 16:57:49 +0900 Subject: [PATCH 696/961] Add test coverage of legacy sample point recreation --- .../Formats/LegacyBeatmapEncoderTest.cs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 855a75117d..812b20d447 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -14,6 +14,7 @@ using osu.Framework.IO.Stores; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Formats; +using osu.Game.Beatmaps.Legacy; using osu.Game.IO; using osu.Game.IO.Serialization; using osu.Game.Rulesets.Catch; @@ -76,6 +77,32 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(decodedSlider.Path.ControlPoints.Count, Is.EqualTo(5)); } + [TestCaseSource(nameof(allBeatmaps))] + public void TestEncodeDecodeStabilityWithNonLegacyControlPoints(string name) + { + var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name); + + sort(decoded.beatmap); + + var originalSerialized = decoded.beatmap.Serialize(); + var encoded = encodeToLegacy(decoded); + + Assert.AreEqual(typeof(LegacyControlPointInfo), decoded.beatmap.ControlPointInfo.GetType()); + + // emulate non-legacy control points by cloning the non-legacy portion. + // the assertion is that the encoder can recreate this losslessly from hitobject data. + decoded.beatmap.ControlPointInfo = decoded.beatmap.ControlPointInfo.DeepClone(); + + Assert.AreNotEqual(typeof(LegacyControlPointInfo), decoded.beatmap.ControlPointInfo.GetType()); + + var decodedAfterEncode = decodeFromLegacy(encoded, name); + + sort(decodedAfterEncode.beatmap); + + Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(originalSerialized)); + Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); + } + private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b) { // equal to null, no need to SequenceEqual @@ -116,7 +143,7 @@ namespace osu.Game.Tests.Beatmaps.Formats } } - private Stream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap) + private MemoryStream encodeToLegacy((IBeatmap beatmap, ISkin beatmapSkin) fullBeatmap) { var (beatmap, beatmapSkin) = fullBeatmap; var stream = new MemoryStream(); From 4da2dca33918ebfc5b57e9f0c30ddd6f06927fd5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 17:21:05 +0900 Subject: [PATCH 697/961] Apply the default `SampleControlPoint` if not externally provided This is mostly to handle tests for now, as generally this should be provided by an external source in all other cases. --- osu.Game/Rulesets/Objects/HitObject.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index 3e95659243..fb1b6cd267 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -112,6 +112,10 @@ namespace osu.Game.Rulesets.Objects // This is done here since ApplyDefaultsToSelf may be used to determine the end time SampleControlPoint = legacyInfo.SamplePointAt(this.GetEndTime() + control_point_leniency); } + else + { + SampleControlPoint ??= SampleControlPoint.DEFAULT; + } nestedHitObjects.Clear(); From 9fae2c350d0eef1ae7e365e9bc636a76a672135f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 17:25:36 +0900 Subject: [PATCH 698/961] Fix test regressions --- osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs index 41a8f72305..4ab6e5cef6 100644 --- a/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs +++ b/osu.Game.Tests/Editing/Checks/CheckMutedObjectsTest.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Game.Audio; using osu.Game.Beatmaps; using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Legacy; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Checks; using osu.Game.Rulesets.Objects; @@ -30,7 +31,7 @@ namespace osu.Game.Tests.Editing.Checks { check = new CheckMutedObjects(); - cpi = new ControlPointInfo(); + cpi = new LegacyControlPointInfo(); cpi.Add(0, new SampleControlPoint { SampleVolume = volume_regular }); cpi.Add(1000, new SampleControlPoint { SampleVolume = volume_low }); cpi.Add(2000, new SampleControlPoint { SampleVolume = volume_muted }); From 1aeae2b8c8537927bc9c93553abddf3c1c935b24 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Mon, 30 Aug 2021 10:11:41 +0100 Subject: [PATCH 699/961] reverse ternary operator --- osu.Game/Overlays/UserProfileOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/UserProfileOverlay.cs b/osu.Game/Overlays/UserProfileOverlay.cs index 6e74acc96a..b0327987f2 100644 --- a/osu.Game/Overlays/UserProfileOverlay.cs +++ b/osu.Game/Overlays/UserProfileOverlay.cs @@ -118,7 +118,7 @@ namespace osu.Game.Overlays if (fetchOnline) { - userReq = user.Username != null ? new GetUserRequest(user.Username) : new GetUserRequest(user.Id); + userReq = user.Id > 1 ? new GetUserRequest(user.Id) : new GetUserRequest(user.Username); userReq.Success += userLoadComplete; API.Queue(userReq); } From 015df282fe61d700aa1ecb8bc41c8200021d3d67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 18:32:55 +0900 Subject: [PATCH 700/961] Simplify copy operations --- .../Visual/Editing/TestSceneEditorSeeking.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 11 +---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs index 96ce418851..ff741a8ed5 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSeeking.cs @@ -21,7 +21,7 @@ namespace osu.Game.Tests.Visual.Editing beatmap.BeatmapInfo.BeatDivisor = 1; - beatmap.ControlPointInfo = new ControlPointInfo(); + beatmap.ControlPointInfo.Clear(); beatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }); beatmap.ControlPointInfo.Add(2000, new TimingControlPoint { BeatLength = 500 }); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index ec08c4a3f3..accefb2583 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -401,15 +401,8 @@ namespace osu.Game.Beatmaps.Formats private readonly HashSet pendingControlPointTypes = new HashSet(); private double pendingControlPointsTime; - private readonly LegacyControlPointInfo controlPointInfo = new LegacyControlPointInfo(); - private void addControlPoint(double time, ControlPoint point, bool timingChange) { - if (point is SampleControlPoint) - { - controlPointInfo.Add(time, point); - } - if (time != pendingControlPointsTime) flushPendingPoints(); @@ -447,9 +440,7 @@ namespace osu.Game.Beatmaps.Formats if (obj != null) { - // assign legacy control points directly to hitobject - //obj.SampleControlPoint = controlPointInfo.SamplePointAt(obj.StartTime); - obj.ApplyDefaults(controlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); + obj.ApplyDefaults(beatmap.ControlPointInfo, beatmap.BeatmapInfo.BaseDifficulty); beatmap.HitObjects.Add(obj); } From 1aaea7011ae2bc308913a59523503f549b67deee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 18:33:05 +0900 Subject: [PATCH 701/961] Fix early return causing event loss in case of multiple control points in group --- osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs index fdfc22700a..5152549bed 100644 --- a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs +++ b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs @@ -46,10 +46,7 @@ namespace osu.Game.Beatmaps.Legacy protected override void GroupItemAdded(ControlPoint controlPoint) { if (controlPoint is SampleControlPoint typed) - { samplePoints.Add(typed); - return; - } base.GroupItemAdded(controlPoint); } @@ -57,10 +54,7 @@ namespace osu.Game.Beatmaps.Legacy protected override void GroupItemRemoved(ControlPoint controlPoint) { if (controlPoint is SampleControlPoint typed) - { samplePoints.Remove(typed); - return; - } base.GroupItemRemoved(controlPoint); } From 04bf667d0db6de78dfb8e3e17a0f3d371d42023b Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Mon, 30 Aug 2021 17:49:18 +0800 Subject: [PATCH 702/961] Parse partially typed enum names in filter query --- osu.Game/Screens/Select/FilterQueryParser.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 72d10019b2..591a632a7c 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -3,8 +3,8 @@ using System; using System.Globalization; +using System.Linq; using System.Text.RegularExpressions; -using osu.Game.Beatmaps; using osu.Game.Screens.Select.Filter; namespace osu.Game.Screens.Select @@ -64,8 +64,7 @@ namespace osu.Game.Screens.Select return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt); case "status": - return TryUpdateCriteriaRange(ref criteria.OnlineStatus, op, value, - (string s, out BeatmapSetOnlineStatus val) => Enum.TryParse(value, true, out val)); + return TryUpdateCriteriaRange(ref criteria.OnlineStatus, op, value, tryParseEnum); case "creator": return TryUpdateCriteriaText(ref criteria.Creator, op, value); @@ -120,6 +119,14 @@ namespace osu.Game.Screens.Select private static bool tryParseInt(string value, out int result) => int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result); + private static bool tryParseEnum(string value, out TEnum result) where TEnum : struct + { + if (Enum.TryParse(value, true, out result)) return true; + + string status = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); + return Enum.TryParse(status, true, out result); + } + /// /// Attempts to parse a keyword filter with the specified and textual . /// If the value indicates a valid textual filter, the function returns true and the resulting data is stored into From 47061c0210ad37b80ba5778bf205ca91dcc0b132 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 18:57:30 +0900 Subject: [PATCH 703/961] Trigger refresh on scoring mode change --- .../BeatmapSet/Scores/ScoresContainer.cs | 71 ++++++++++++------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index aff48919b4..bfdb90c36a 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -12,8 +12,11 @@ using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Framework.Bindables; +using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; @@ -27,6 +30,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly Bindable ruleset = new Bindable(); private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global); private readonly IBindable user = new Bindable(); + private readonly Bindable scoringMode = new Bindable(); private readonly Box background; private readonly ScoreTable scoreTable; @@ -42,35 +46,20 @@ namespace osu.Game.Overlays.BeatmapSet.Scores [Resolved] private RulesetStore rulesets { get; set; } + [Resolved] + private ScoreManager scoreManager { get; set; } + private GetScoresRequest getScoresRequest; + private APILegacyScores scores; + protected APILegacyScores Scores { - set => Schedule(() => + set { - topScoresContainer.Clear(); - - if (value?.Scores.Any() != true) - { - scoreTable.ClearScores(); - scoreTable.Hide(); - return; - } - - var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList(); - var topScore = scoreInfos.First(); - - scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); - scoreTable.Show(); - - var userScore = value.UserScore; - var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); - - topScoresContainer.Add(new DrawableTopScore(topScore)); - - if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); - }); + scores = value; + displayScores(value); + } } public ScoresContainer() @@ -166,11 +155,12 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, OsuConfigManager config) { background.Colour = colourProvider.Background5; user.BindTo(api.LocalUser); + config.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); } protected override void LoadComplete() @@ -183,6 +173,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Beatmap.BindValueChanged(onBeatmapChanged); user.BindValueChanged(onUserChanged, true); + + scoringMode.BindValueChanged(_ => displayScores(scores)); } private void onBeatmapChanged(ValueChangedEvent beatmap) @@ -254,6 +246,35 @@ namespace osu.Game.Overlays.BeatmapSet.Scores api.Queue(getScoresRequest); } + private void displayScores(APILegacyScores newScores) + { + Schedule(() => + { + topScoresContainer.Clear(); + + if (newScores?.Scores.Any() != true) + { + scoreTable.ClearScores(); + scoreTable.Hide(); + return; + } + + var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList(); + var topScore = scoreInfos.First(); + + scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); + scoreTable.Show(); + + var userScore = newScores.UserScore; + var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); + + topScoresContainer.Add(new DrawableTopScore(topScore)); + + if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); + }); + } + private bool userIsSupporter => api.IsLoggedIn && api.LocalUser.Value.IsSupporter; } } From b217dd1a658b590625a913f361e596ea8587a82c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:03:16 +0900 Subject: [PATCH 704/961] Order scores by score --- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index bfdb90c36a..1e5f7c3f72 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -259,7 +259,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores return; } - var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList(); + var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)) + .OrderByDescending(s => scoreManager.GetBindableTotalScore(s).Value) + .ToList(); + var topScore = scoreInfos.First(); scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); From 8137eee527e93bc5963533b0ea3404cde110c4b1 Mon Sep 17 00:00:00 2001 From: Henry Lin Date: Mon, 30 Aug 2021 18:05:47 +0800 Subject: [PATCH 705/961] Reuse `value` to save enum name Co-authored-by: Salman Ahmed --- osu.Game/Screens/Select/FilterQueryParser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Select/FilterQueryParser.cs b/osu.Game/Screens/Select/FilterQueryParser.cs index 591a632a7c..a882148392 100644 --- a/osu.Game/Screens/Select/FilterQueryParser.cs +++ b/osu.Game/Screens/Select/FilterQueryParser.cs @@ -123,8 +123,8 @@ namespace osu.Game.Screens.Select { if (Enum.TryParse(value, true, out result)) return true; - string status = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); - return Enum.TryParse(status, true, out result); + value = Enum.GetNames(typeof(TEnum)).FirstOrDefault(name => name.StartsWith(value, true, CultureInfo.InvariantCulture)); + return Enum.TryParse(value, true, out result); } /// From d03950fb370869e18f2e9050b2148a06b0393084 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:33:09 +0900 Subject: [PATCH 706/961] Move score calculation to ScoreManager --- osu.Game/Scoring/ScoreManager.cs | 144 ++++++++++++++----------------- 1 file changed, 67 insertions(+), 77 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 83bcac01ac..f310462d6e 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -34,6 +34,7 @@ namespace osu.Game.Scoring protected override string ImportFromStablePath => Path.Combine("Data", "r"); + private readonly Bindable scoringMode = new Bindable(); private readonly RulesetStore rulesets; private readonly Func beatmaps; @@ -51,6 +52,8 @@ namespace osu.Game.Scoring this.beatmaps = beatmaps; this.difficulties = difficulties; this.configManager = configManager; + + configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); } protected override ScoreInfo CreateModel(ArchiveReader archive) @@ -113,7 +116,7 @@ namespace osu.Game.Scoring /// The bindable containing the total score. public Bindable GetBindableTotalScore(ScoreInfo score) { - var bindable = new TotalScoreBindable(score, difficulties); + var bindable = new TotalScoreBindable(score, this); configManager?.BindWith(OsuSetting.ScoreDisplayMode, bindable.ScoringMode); return bindable; } @@ -128,6 +131,63 @@ namespace osu.Game.Scoring /// The bindable containing the formatted total score string. public Bindable GetBindableTotalScoreString(ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score)); + public long GetTotalScore(ScoreInfo score) => GetTotalScoreAsync(score).Result; + + public async Task GetTotalScoreAsync(ScoreInfo score, CancellationToken cancellationToken = default) + { + if (score.Beatmap == null) + return score.TotalScore; + + int beatmapMaxCombo; + double accuracy = score.Accuracy; + + if (score.IsLegacyScore) + { + if (score.RulesetID == 3) + { + // In osu!stable, a full-GREAT score has 100% accuracy in mania. Along with a full combo, the score becomes indistinguishable from a full-PERFECT score. + // To get around this, recalculate accuracy based on the hit statistics. + // Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together. + double maxBaseScore = score.Statistics.Select(kvp => kvp.Value).Sum() * Judgement.ToNumericResult(HitResult.Perfect); + double baseScore = score.Statistics.Select(kvp => Judgement.ToNumericResult(kvp.Key) * kvp.Value).Sum(); + if (maxBaseScore > 0) + accuracy = baseScore / maxBaseScore; + } + + // This score is guaranteed to be an osu!stable score. + // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. + if (score.Beatmap.MaxCombo != null) + beatmapMaxCombo = score.Beatmap.MaxCombo.Value; + else + { + if (score.Beatmap.ID == 0 || difficulties == null) + { + // We don't have enough information (max combo) to compute the score, so use the provided score. + return score.TotalScore; + } + + // We can compute the max combo locally after the async beatmap difficulty computation. + var difficulty = await difficulties().GetDifficultyAsync(score.Beatmap, score.Ruleset, score.Mods, cancellationToken).ConfigureAwait(false); + beatmapMaxCombo = difficulty.MaxCombo; + } + } + else + { + // This is guaranteed to be a non-legacy score. + // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. + beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); + } + + if (beatmapMaxCombo == 0) + return 0; + + var ruleset = score.Ruleset.CreateInstance(); + var scoreProcessor = ruleset.CreateScoreProcessor(); + scoreProcessor.Mods.Value = score.Mods; + + return (long)Math.Round(scoreProcessor.GetScore(scoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics)); + } + /// /// Provides the total score of a . Responds to changes in the currently-selected . /// @@ -136,99 +196,29 @@ namespace osu.Game.Scoring public readonly Bindable ScoringMode = new Bindable(); private readonly ScoreInfo score; - private readonly Func difficulties; + private readonly ScoreManager scoreManager; /// /// Creates a new . /// /// The to provide the total score of. - /// A function to retrieve the . - public TotalScoreBindable(ScoreInfo score, Func difficulties) + /// The . + public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager) { this.score = score; - this.difficulties = difficulties; + this.scoreManager = scoreManager; ScoringMode.BindValueChanged(onScoringModeChanged, true); } - private IBindable difficultyBindable; private CancellationTokenSource difficultyCancellationSource; private void onScoringModeChanged(ValueChangedEvent mode) { difficultyCancellationSource?.Cancel(); - difficultyCancellationSource = null; + difficultyCancellationSource = new CancellationTokenSource(); - if (score.Beatmap == null) - { - Value = score.TotalScore; - return; - } - - int beatmapMaxCombo; - double accuracy = score.Accuracy; - - if (score.IsLegacyScore) - { - if (score.RulesetID == 3) - { - // In osu!stable, a full-GREAT score has 100% accuracy in mania. Along with a full combo, the score becomes indistinguishable from a full-PERFECT score. - // To get around this, recalculate accuracy based on the hit statistics. - // Note: This cannot be applied universally to all legacy scores, as some rulesets (e.g. catch) group multiple judgements together. - double maxBaseScore = score.Statistics.Select(kvp => kvp.Value).Sum() * Judgement.ToNumericResult(HitResult.Perfect); - double baseScore = score.Statistics.Select(kvp => Judgement.ToNumericResult(kvp.Key) * kvp.Value).Sum(); - if (maxBaseScore > 0) - accuracy = baseScore / maxBaseScore; - } - - // This score is guaranteed to be an osu!stable score. - // The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used. - if (score.Beatmap.MaxCombo == null) - { - if (score.Beatmap.ID == 0 || difficulties == null) - { - // We don't have enough information (max combo) to compute the score, so use the provided score. - Value = score.TotalScore; - return; - } - - // We can compute the max combo locally after the async beatmap difficulty computation. - difficultyBindable = difficulties().GetBindableDifficulty(score.Beatmap, score.Ruleset, score.Mods, (difficultyCancellationSource = new CancellationTokenSource()).Token); - difficultyBindable.BindValueChanged(d => - { - if (d.NewValue is StarDifficulty diff) - updateScore(diff.MaxCombo, accuracy); - }, true); - - return; - } - - beatmapMaxCombo = score.Beatmap.MaxCombo.Value; - } - else - { - // This is guaranteed to be a non-legacy score. - // The combo must be determined through the score's statistics, as both the beatmap's max combo and the difficulty calculator will provide osu!stable combo values. - beatmapMaxCombo = Enum.GetValues(typeof(HitResult)).OfType().Where(r => r.AffectsCombo()).Select(r => score.Statistics.GetValueOrDefault(r)).Sum(); - } - - updateScore(beatmapMaxCombo, accuracy); - } - - private void updateScore(int beatmapMaxCombo, double accuracy) - { - if (beatmapMaxCombo == 0) - { - Value = 0; - return; - } - - var ruleset = score.Ruleset.CreateInstance(); - var scoreProcessor = ruleset.CreateScoreProcessor(); - - scoreProcessor.Mods.Value = score.Mods; - - Value = (long)Math.Round(scoreProcessor.GetScore(ScoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics)); + scoreManager.GetTotalScoreAsync(score, difficultyCancellationSource.Token).ContinueWith(s => Value = s.Result, TaskContinuationOptions.OnlyOnRanToCompletion); } } From 458ce250f01c7d81f05c78d2382d1151726cc82a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:34:12 +0900 Subject: [PATCH 707/961] Use new ScoreManager method in ScoreTable --- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 4 ++-- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index a154016824..847df53edc 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -151,8 +151,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores new OsuSpriteText { Margin = new MarginPadding { Right = horizontal_inset }, - Current = scoreManager.GetBindableTotalScoreString(score), - Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium) + Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium), + Text = scoreManager.GetTotalScore(score).ToLocalisableString(@"N0"), }, new OsuSpriteText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 1e5f7c3f72..a0ccb5a393 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -260,7 +260,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)) - .OrderByDescending(s => scoreManager.GetBindableTotalScore(s).Value) + .OrderByDescending(s => scoreManager.GetTotalScore(s)) .ToList(); var topScore = scoreInfos.First(); From 4ebb11472df20b65efc4e0f13cfb4bac6f7a6878 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:34:34 +0900 Subject: [PATCH 708/961] Update Leaderboard to reorder scores based on scoring mode --- osu.Game/Online/Leaderboards/Leaderboard.cs | 8 +++++++- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 2 +- .../Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 4 ++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 4f8b27602b..f3a06994ee 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -13,11 +13,13 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Threading; +using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Placeholders; +using osu.Game.Rulesets.Scoring; using osuTK; using osuTK.Graphics; @@ -27,6 +29,7 @@ namespace osu.Game.Online.Leaderboards { private const double fade_duration = 300; + private readonly Bindable scoringMode = new Bindable(); private readonly OsuScrollContainer scrollContainer; private readonly Container placeholderContainer; private readonly UserTopScoreContainer topScoreContainer; @@ -246,12 +249,15 @@ namespace osu.Game.Online.Leaderboards private readonly IBindable apiState = new Bindable(); [BackgroundDependencyLoader] - private void load() + private void load(OsuConfigManager configManager) { if (api != null) apiState.BindTo(api.State); apiState.BindValueChanged(onlineStateChanged, true); + + configManager.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); + scoringMode.BindValueChanged(_ => RefreshScores(), true); } private APIRequest getScoresRequest; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 934b905a1a..206b0e7936 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -198,8 +198,8 @@ namespace osu.Game.Online.Leaderboards { TextColour = Color4.White, GlowColour = Color4Extensions.FromHex(@"83ccfa"), - Current = scoreManager.GetBindableTotalScoreString(score), Font = OsuFont.Numeric.With(size: 23), + Text = scoreManager.GetTotalScore(score).ToLocalisableString(@"N0"), }, RankContainer = new Container { diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index a86a614a05..04e7172519 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -146,7 +146,7 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); } - Scores = scores.OrderByDescending(s => s.TotalScore).ToArray(); + Scores = scores.OrderByDescending(s => scoreManager.GetTotalScore(s)).ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; return null; @@ -182,7 +182,7 @@ namespace osu.Game.Screens.Select.Leaderboards req.Success += r => { - scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets))); + scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).OrderByDescending(s => scoreManager.GetTotalScore(s))); TopScore = r.UserScore?.CreateScoreInfo(rulesets); }; From e19d81c88ce21aba8cf19219142a60a9ff356236 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:41:44 +0900 Subject: [PATCH 709/961] Fix potential incorrect ordering --- .../Overlays/BeatmapSet/Scores/ScoresContainer.cs | 1 + .../Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index a0ccb5a393..91c3dfad65 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -261,6 +261,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)) .OrderByDescending(s => scoreManager.GetTotalScore(s)) + .ThenBy(s => s.OnlineScoreID) .ToList(); var topScore = scoreInfos.First(); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 04e7172519..0276ae8b2a 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -146,7 +146,10 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); } - Scores = scores.OrderByDescending(s => scoreManager.GetTotalScore(s)).ToArray(); + Scores = scores.OrderByDescending(s => scoreManager.GetTotalScore(s)) + .ThenBy(s => s.OnlineScoreID) + .ToArray(); + PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; return null; @@ -182,7 +185,11 @@ namespace osu.Game.Screens.Select.Leaderboards req.Success += r => { - scoresCallback?.Invoke(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).OrderByDescending(s => scoreManager.GetTotalScore(s))); + scoresCallback?.Invoke( + r.Scores.Select(s => s.CreateScoreInfo(rulesets)) + .OrderByDescending(s => scoreManager.GetTotalScore(s)) + .ThenBy(s => s.OnlineScoreID)); + TopScore = r.UserScore?.CreateScoreInfo(rulesets); }; From caa797cbf46ad46d45832a14b709a8b9641fea6f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 30 Aug 2021 19:58:35 +0900 Subject: [PATCH 710/961] Attempt to reorder score panel list --- osu.Game/Screens/Ranking/ScorePanelList.cs | 48 +++++++++++++++------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index e170241ede..c9ddfd27d3 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -5,11 +5,14 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Game.Configuration; using osu.Game.Graphics.Containers; +using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osuTK; using osuTK.Input; @@ -289,27 +292,42 @@ namespace osu.Game.Screens.Ranking { public override IEnumerable FlowingChildren => applySorting(AliveInternalChildren); + private readonly Bindable scoringMode = new Bindable(); + + [Resolved] + private ScoreManager scoreManager { get; set; } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager configManager) + { + configManager.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + scoringMode.BindValueChanged(mode => + { + foreach (var c in Children) + SetLayoutPosition(c, scoreManager.GetTotalScore(c.Panel.Score)); + }, true); + } + public int GetPanelIndex(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Panel.Score != score).Count(); - private IEnumerable applySorting(IEnumerable drawables) => drawables.OfType() - .OrderByDescending(s => s.Panel.Score.TotalScore) - .ThenBy(s => s.Panel.Score.OnlineScoreID); - - protected override int Compare(Drawable x, Drawable y) + public override void Add(ScorePanelTrackingContainer drawable) { - var tX = (ScorePanelTrackingContainer)x; - var tY = (ScorePanelTrackingContainer)y; + Debug.Assert(drawable != null); - int result = tY.Panel.Score.TotalScore.CompareTo(tX.Panel.Score.TotalScore); + base.Add(drawable); - if (result != 0) - return result; - - if (tX.Panel.Score.OnlineScoreID == null || tY.Panel.Score.OnlineScoreID == null) - return base.Compare(x, y); - - return tX.Panel.Score.OnlineScoreID.Value.CompareTo(tY.Panel.Score.OnlineScoreID.Value); + SetLayoutPosition(drawable, scoreManager?.GetTotalScore(drawable.Panel.Score) ?? 0); } + + private IEnumerable applySorting(IEnumerable drawables) => drawables.OfType() + .OrderByDescending(GetLayoutPosition) + .ThenBy(s => s.Panel.Score.OnlineScoreID); } private class Scroll : OsuScrollContainer From c789163d01e367f867e8f4a754516c6e895ade24 Mon Sep 17 00:00:00 2001 From: rednir Date: Mon, 30 Aug 2021 13:22:12 +0100 Subject: [PATCH 711/961] use user ID overload when its supposed to be used Co-authored-by: Salman Ahmed --- osu.Game/OsuGame.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 26fa1d5a4c..1e6e1e0ead 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -329,7 +329,11 @@ namespace osu.Game break; case LinkAction.OpenUserProfile: - ShowUser(link.Argument); + if (int.TryParse(link.Argument, out var userId)) + ShowUser(userId); + else + ShowUser(link.Argument); + break; case LinkAction.OpenWiki: From 8104b15874c5b358c22f7d3f8d6fb9ac42b09b94 Mon Sep 17 00:00:00 2001 From: rednir Date: Mon, 30 Aug 2021 13:23:33 +0100 Subject: [PATCH 712/961] remove braces Co-authored-by: Salman Ahmed --- osu.Game/Online/API/Requests/GetUserRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 48041cd40c..0c8a4a3578 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -27,6 +27,6 @@ namespace osu.Game.Online.API.Requests Ruleset = ruleset; } - protected override string Target => (userIdentifier != null) ? $@"users/{userIdentifier}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; + protected override string Target => userIdentifier != null ? $@"users/{userIdentifier}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; } } From a2cff75fc0183f0c0e899f2fc0cba05c1898779e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 30 Aug 2021 21:55:08 +0900 Subject: [PATCH 713/961] Fix editor not cloning control points as expected --- .../Beatmaps/Formats/LegacyBeatmapEncoderTest.cs | 7 ++++++- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 812b20d447..e66221514c 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -91,7 +91,12 @@ namespace osu.Game.Tests.Beatmaps.Formats // emulate non-legacy control points by cloning the non-legacy portion. // the assertion is that the encoder can recreate this losslessly from hitobject data. - decoded.beatmap.ControlPointInfo = decoded.beatmap.ControlPointInfo.DeepClone(); + var controlPointInfo = new ControlPointInfo(); + + foreach (var point in decoded.beatmap.ControlPointInfo.AllControlPoints) + controlPointInfo.Add(point.Time, point.DeepClone()); + + decoded.beatmap.ControlPointInfo = controlPointInfo; Assert.AreNotEqual(typeof(LegacyControlPointInfo), decoded.beatmap.ControlPointInfo.GetType()); diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index d2a3b2fc8b..3ff40fe194 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -324,7 +324,7 @@ namespace osu.Game.Beatmaps.ControlPoints public ControlPointInfo DeepClone() { - var controlPointInfo = new ControlPointInfo(); + var controlPointInfo = (ControlPointInfo)Activator.CreateInstance(GetType()); foreach (var point in AllControlPoints) controlPointInfo.Add(point.Time, point.DeepClone()); From acf38c723a5fd681ba62c83cf1629f4d26783629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 14:11:57 +0200 Subject: [PATCH 714/961] Move labelled dropdown from tournament to main game --- .../Screens/Setup/SetupScreen.cs | 22 ------------- .../UserInterfaceV2/LabelledDropdown.cs | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+), 22 deletions(-) create mode 100644 osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index 5d8f0405ca..f6d28c15e0 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -1,14 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using System.Drawing; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Overlays; @@ -131,25 +129,5 @@ namespace osu.Game.Tournament.Screens.Setup resolution.Value = $"{ScreenSpaceDrawQuad.Width:N0}x{ScreenSpaceDrawQuad.Height:N0}"; } - - public class LabelledDropdown : LabelledComponent, T> - { - public LabelledDropdown() - : base(true) - { - } - - public IEnumerable Items - { - get => Component.Items; - set => Component.Items = value; - } - - protected override OsuDropdown CreateComponent() => new OsuDropdown - { - RelativeSizeAxes = Axes.X, - Width = 0.5f, - }; - } } } diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs new file mode 100644 index 0000000000..44f09f13eb --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDropdown.cs @@ -0,0 +1,31 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class LabelledDropdown : LabelledComponent, TItem> + { + public LabelledDropdown() + : base(true) + { + } + + public IEnumerable Items + { + get => Component.Items; + set => Component.Items = value; + } + + protected sealed override OsuDropdown CreateComponent() => CreateDropdown().With(d => + { + d.RelativeSizeAxes = Axes.X; + d.Width = 0.5f; + }); + + protected virtual OsuDropdown CreateDropdown() => new OsuDropdown(); + } +} From a6d09b0bb0d4f05533baf2b658b22076e4791c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 14:12:10 +0200 Subject: [PATCH 715/961] Add labelled enum dropdown variant --- .../UserInterfaceV2/LabelledEnumDropdown.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs new file mode 100644 index 0000000000..b818c394ae --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledEnumDropdown.cs @@ -0,0 +1,14 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class LabelledEnumDropdown : LabelledDropdown + where TEnum : struct, Enum + { + protected override OsuDropdown CreateDropdown() => new OsuEnumDropdown(); + } +} From 89429021c999913a057c73d8d3eb263c02ff6bdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 14:12:17 +0200 Subject: [PATCH 716/961] Add test scene for labelled dropdowns --- .../TestSceneLabelledDropdown.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs new file mode 100644 index 0000000000..4b74e37ec4 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneLabelledDropdown.cs @@ -0,0 +1,34 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterfaceV2; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneLabelledDropdown : OsuTestScene + { + [Test] + public void TestLabelledDropdown() + => AddStep(@"create dropdown", () => Child = new LabelledDropdown + { + Label = @"Countdown speed", + Items = new[] + { + @"Half", + @"Normal", + @"Double" + }, + Description = @"This is a description" + }); + + [Test] + public void TestLabelledEnumDropdown() + => AddStep(@"create dropdown", () => Child = new LabelledEnumDropdown + { + Label = @"Beatmap status", + Description = @"This is a description" + }); + } +} From 48e56adcfe500c6f72d653aa170ea1dbcd2f817a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 15:53:30 +0200 Subject: [PATCH 717/961] Add labelled number box control --- .../Graphics/UserInterfaceV2/LabelledNumberBox.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.cs new file mode 100644 index 0000000000..ca247ab679 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/LabelledNumberBox.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.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class LabelledNumberBox : LabelledTextBox + { + protected override OsuTextBox CreateTextBox() => new OsuNumberBox(); + } +} From eec9f6d19168adbc563b443ab0429c8aa7bdb2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 15:53:48 +0200 Subject: [PATCH 718/961] Add countdown settings to design section --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 68aaf3dd76..633196ff2e 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -1,14 +1,28 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using System.Globalization; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; +using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterfaceV2; +using osuTK; namespace osu.Game.Screens.Edit.Setup { internal class DesignSection : SetupSection { + private const float fade_duration = 250; + + private LabelledSwitchButton enableCountdown; + private FillFlowContainer countdownSettings; + private LabelledEnumDropdown countdownSpeed; + private LabelledNumberBox countdownOffset; + private LabelledSwitchButton widescreenSupport; private LabelledSwitchButton epilepsyWarning; private LabelledSwitchButton letterboxDuringBreaks; @@ -20,6 +34,35 @@ namespace osu.Game.Screens.Edit.Setup { Children = new[] { + enableCountdown = new LabelledSwitchButton + { + Label = "Enable countdown", + Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None }, + Description = "If enabled, an \"Are you ready? 3, 2, 1, GO!\" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." + }, + countdownSettings = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(10), + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + countdownSpeed = new LabelledEnumDropdown + { + Label = "Countdown speed", + Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal }, + Items = Enum.GetValues(typeof(CountdownType)).Cast().Where(type => type != CountdownType.None) + }, + countdownOffset = new LabelledNumberBox + { + Label = "Countdown offset", + Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() }, + Description = "If the countdown sounds off-time, use this to make it appear one or more beats early.", + } + } + }, + Empty(), widescreenSupport = new LabelledSwitchButton { Label = "Widescreen support", @@ -45,13 +88,34 @@ namespace osu.Game.Screens.Edit.Setup { base.LoadComplete(); + enableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true); + countdownSettings.FinishTransforms(true); + + enableCountdown.Current.BindValueChanged(_ => updateBeatmap()); + countdownSpeed.Current.BindValueChanged(_ => updateBeatmap()); + countdownOffset.OnCommit += (_, __) => updateBeatmap(); + widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); } + private void updateCountdownSettingsVisibility() + { + bool countdownEnabled = enableCountdown.Current.Value; + + foreach (var child in countdownSettings) + { + child.ScaleTo(new Vector2(1, countdownEnabled ? 1 : 0), fade_duration, Easing.OutQuint) + .FadeTo(countdownEnabled ? 1 : 0, fade_duration, Easing.OutQuint); + } + } + private void updateBeatmap() { + Beatmap.BeatmapInfo.Countdown = enableCountdown.Current.Value ? countdownSpeed.Current.Value : CountdownType.None; + Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(countdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0; + Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value; Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value; From b43ee2d61c20a20c9ff464b2a2a15c9ff0e23579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 29 Aug 2021 17:20:25 +0200 Subject: [PATCH 719/961] Add descriptions to enum members --- osu.Game/Beatmaps/CountdownType.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/osu.Game/Beatmaps/CountdownType.cs b/osu.Game/Beatmaps/CountdownType.cs index 1831b4576b..73f85bf701 100644 --- a/osu.Game/Beatmaps/CountdownType.cs +++ b/osu.Game/Beatmaps/CountdownType.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.ComponentModel; + namespace osu.Game.Beatmaps { /// @@ -9,8 +11,14 @@ namespace osu.Game.Beatmaps public enum CountdownType { None = 0, + + [Description("Normal")] Normal = 1, + + [Description("Half speed")] HalfSpeed = 2, + + [Description("Double speed")] DoubleSpeed = 3 } } From ddf9d2aa6ca18d1212e8bd97c8743aacac026d88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 29 Aug 2021 18:01:40 +0200 Subject: [PATCH 720/961] Add test coverage --- .../Visual/Editing/TestSceneDesignSection.cs | 97 +++++++++++++++++++ osu.Game/Screens/Edit/Setup/DesignSection.cs | 36 ++++--- 2 files changed, 119 insertions(+), 14 deletions(-) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs new file mode 100644 index 0000000000..d84ffa1052 --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs @@ -0,0 +1,97 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Globalization; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Framework.Graphics.UserInterface; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Setup; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneDesignSection : OsuManualInputManagerTestScene + { + private TestDesignSection designSection; + private EditorBeatmap editorBeatmap { get; set; } + + [SetUpSteps] + public void SetUp() + { + AddStep("create blank beatmap", () => editorBeatmap = new EditorBeatmap(new Beatmap())); + AddStep("create section", () => Child = new DependencyProvidingContainer + { + RelativeSizeAxes = Axes.Both, + CachedDependencies = new (Type, object)[] + { + (typeof(EditorBeatmap), editorBeatmap) + }, + Child = designSection = new TestDesignSection() + }); + } + + [Test] + public void TestCountdownOff() + { + AddStep("turn countdown off", () => designSection.EnableCountdown.Current.Value = false); + + AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.None); + AddUntilStep("other controls hidden", () => !designSection.CountdownSpeed.IsPresent && !designSection.CountdownOffset.IsPresent); + } + + [Test] + public void TestCountdownOn() + { + AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true); + + AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal); + AddUntilStep("other controls shown", () => designSection.CountdownSpeed.IsPresent && designSection.CountdownOffset.IsPresent); + + AddStep("change countdown speed", () => designSection.CountdownSpeed.Current.Value = CountdownType.DoubleSpeed); + + AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.DoubleSpeed); + AddUntilStep("other controls still shown", () => designSection.CountdownSpeed.IsPresent && designSection.CountdownOffset.IsPresent); + } + + [Test] + public void TestCountdownOffset() + { + AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true); + + AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal); + + checkOffsetAfter("1", 1); + checkOffsetAfter(string.Empty, 0); + checkOffsetAfter("123", 123); + checkOffsetAfter("0", 0); + } + + private void checkOffsetAfter(string userInput, int expectedFinalValue) + { + AddStep("click text box", () => + { + var textBox = designSection.CountdownOffset.ChildrenOfType().Single(); + InputManager.MoveMouseTo(textBox); + InputManager.Click(MouseButton.Left); + }); + AddStep("set offset text", () => designSection.CountdownOffset.Current.Value = userInput); + AddStep("commit text", () => InputManager.Key(Key.Enter)); + + AddAssert($"displayed value is {expectedFinalValue}", () => designSection.CountdownOffset.Current.Value == expectedFinalValue.ToString(CultureInfo.InvariantCulture)); + AddAssert($"beatmap value is {expectedFinalValue}", () => editorBeatmap.BeatmapInfo.CountdownOffset == expectedFinalValue); + } + + private class TestDesignSection : DesignSection + { + public new LabelledSwitchButton EnableCountdown => base.EnableCountdown; + public new LabelledEnumDropdown CountdownSpeed => base.CountdownSpeed; + public new LabelledNumberBox CountdownOffset => base.CountdownOffset; + } + } +} diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 633196ff2e..d030c2a894 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -18,15 +18,16 @@ namespace osu.Game.Screens.Edit.Setup { private const float fade_duration = 250; - private LabelledSwitchButton enableCountdown; - private FillFlowContainer countdownSettings; - private LabelledEnumDropdown countdownSpeed; - private LabelledNumberBox countdownOffset; + protected LabelledSwitchButton EnableCountdown; + protected LabelledEnumDropdown CountdownSpeed; + protected LabelledNumberBox CountdownOffset; private LabelledSwitchButton widescreenSupport; private LabelledSwitchButton epilepsyWarning; private LabelledSwitchButton letterboxDuringBreaks; + private FillFlowContainer countdownSettings; + public override LocalisableString Title => "Design"; [BackgroundDependencyLoader] @@ -34,7 +35,7 @@ namespace osu.Game.Screens.Edit.Setup { Children = new[] { - enableCountdown = new LabelledSwitchButton + EnableCountdown = new LabelledSwitchButton { Label = "Enable countdown", Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None }, @@ -48,13 +49,13 @@ namespace osu.Game.Screens.Edit.Setup Direction = FillDirection.Vertical, Children = new Drawable[] { - countdownSpeed = new LabelledEnumDropdown + CountdownSpeed = new LabelledEnumDropdown { Label = "Countdown speed", Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None ? Beatmap.BeatmapInfo.Countdown : CountdownType.Normal }, Items = Enum.GetValues(typeof(CountdownType)).Cast().Where(type => type != CountdownType.None) }, - countdownOffset = new LabelledNumberBox + CountdownOffset = new LabelledNumberBox { Label = "Countdown offset", Current = { Value = Beatmap.BeatmapInfo.CountdownOffset.ToString() }, @@ -88,12 +89,12 @@ namespace osu.Game.Screens.Edit.Setup { base.LoadComplete(); - enableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true); + EnableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true); countdownSettings.FinishTransforms(true); - enableCountdown.Current.BindValueChanged(_ => updateBeatmap()); - countdownSpeed.Current.BindValueChanged(_ => updateBeatmap()); - countdownOffset.OnCommit += (_, __) => updateBeatmap(); + EnableCountdown.Current.BindValueChanged(_ => updateBeatmap()); + CountdownSpeed.Current.BindValueChanged(_ => updateBeatmap()); + CountdownOffset.OnCommit += (_, __) => onOffsetCommitted(); widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); @@ -102,7 +103,7 @@ namespace osu.Game.Screens.Edit.Setup private void updateCountdownSettingsVisibility() { - bool countdownEnabled = enableCountdown.Current.Value; + bool countdownEnabled = EnableCountdown.Current.Value; foreach (var child in countdownSettings) { @@ -111,10 +112,17 @@ namespace osu.Game.Screens.Edit.Setup } } + private void onOffsetCommitted() + { + updateBeatmap(); + // update displayed text to ensure parsed value matches display (i.e. if empty string was provided). + CountdownOffset.Current.Value = Beatmap.BeatmapInfo.CountdownOffset.ToString(CultureInfo.InvariantCulture); + } + private void updateBeatmap() { - Beatmap.BeatmapInfo.Countdown = enableCountdown.Current.Value ? countdownSpeed.Current.Value : CountdownType.None; - Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(countdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0; + Beatmap.BeatmapInfo.Countdown = EnableCountdown.Current.Value ? CountdownSpeed.Current.Value : CountdownType.None; + Beatmap.BeatmapInfo.CountdownOffset = int.TryParse(CountdownOffset.Current.Value, NumberStyles.None, CultureInfo.InvariantCulture, out int offset) ? offset : 0; Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value; Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; From 570d36fde79c9a0d8d0aa950a1e990fad40b96fa Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 30 Aug 2021 20:53:43 -0700 Subject: [PATCH 721/961] Make toolbar handle mouse events instead --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 4 +++- osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs | 4 ++-- osu.Game/Overlays/Toolbar/Toolbar.cs | 6 ++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index a112534837..b536233ff0 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -345,7 +345,9 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); AddStep("move cursor to toolbar", () => InputManager.MoveMouseTo(Game.Toolbar.ScreenSpaceDrawQuad.Centre)); AddStep("release left mouse button", () => InputManager.ReleaseButton(MouseButton.Left)); - AddAssert("now playing is still visible", () => nowPlayingOverlay.State.Value == Visibility.Visible); + AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden); + + AddStep("press now playing hotkey", () => InputManager.Key(Key.F6)); // toolbar -> background AddStep("press left mouse button", () => InputManager.PressButton(MouseButton.Left)); diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index 0e635d26c2..b9b098df80 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -75,14 +75,14 @@ namespace osu.Game.Graphics.Containers protected override bool OnMouseDown(MouseDownEvent e) { - closeOnMouseUp = !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition) && (game?.Toolbar.IsHovered == false); + closeOnMouseUp = !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition); return base.OnMouseDown(e); } protected override void OnMouseUp(MouseUpEvent e) { - if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition) && (game?.Toolbar.IsHovered == false)) + if (closeOnMouseUp && !base.ReceivePositionalInputAt(e.ScreenSpaceMousePosition)) Hide(); base.OnMouseUp(e); diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 918e3b7105..2664301a0c 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -41,8 +41,7 @@ namespace osu.Game.Overlays.Toolbar // Toolbar and its components need keyboard input even when hidden. public override bool PropagateNonPositionalInputSubTree => true; - // IsHovered is used - public override bool HandlePositionalInput => true; + protected override bool Handle(UIEvent e) => e is MouseEvent; public Toolbar() { @@ -143,13 +142,12 @@ namespace osu.Game.Overlays.Toolbar protected override bool OnHover(HoverEvent e) { gradientBackground.FadeIn(transition_time, Easing.OutQuint); - return base.OnHover(e); + return true; } protected override void OnHoverLost(HoverLostEvent e) { gradientBackground.FadeOut(transition_time, Easing.OutQuint); - base.OnHoverLost(e); } } From 529a9a6ff87eb5a121911502765fb83e515e7462 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 14:08:21 +0900 Subject: [PATCH 722/961] Adjust minimum triangle movement speed to avoid "static" triangles in logo Closes #14584. --- .../Visual/UserInterface/TestSceneOsuLogo.cs | 25 +++++++++++++++++++ osu.Game/Graphics/Backgrounds/Triangles.cs | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs new file mode 100644 index 0000000000..8b91339479 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOsuLogo.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics; +using osu.Game.Screens.Menu; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneOsuLogo : OsuTestScene + { + [Test] + public void TestBasic() + { + AddStep("Add logo", () => + { + Child = new OsuLogo + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + }; + }); + } + } +} diff --git a/osu.Game/Graphics/Backgrounds/Triangles.cs b/osu.Game/Graphics/Backgrounds/Triangles.cs index 269360c492..35c48a50d0 100644 --- a/osu.Game/Graphics/Backgrounds/Triangles.cs +++ b/osu.Game/Graphics/Backgrounds/Triangles.cs @@ -153,7 +153,7 @@ namespace osu.Game.Graphics.Backgrounds TriangleParticle newParticle = parts[i]; // Scale moved distance by the size of the triangle. Smaller triangles should move more slowly. - newParticle.Position.Y += parts[i].Scale * movedDistance; + newParticle.Position.Y += Math.Max(0.5f, parts[i].Scale) * movedDistance; newParticle.Colour.A = adjustedAlpha; parts[i] = newParticle; From c25ab6835caf9aaf1708807b42afeeb6b140b270 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 14:38:35 +0900 Subject: [PATCH 723/961] Remove IJsonSerializable interface Was pretty pointless and made it hard to use the custom serialisation terms arbitrarily in tests. --- osu.Game/Beatmaps/BeatmapInfo.cs | 3 +-- osu.Game/Beatmaps/IBeatmap.cs | 3 +-- ...JsonSerializable.cs => JsonSerializableExtensions.cs} | 9 +-------- osu.Game/Rulesets/Mods/Mod.cs | 3 +-- osu.Game/Rulesets/Timing/MultiplierControlPoint.cs | 3 +-- osu.Game/Screens/Edit/ClipboardContent.cs | 3 +-- osu.Game/Screens/Play/HUD/SkinnableInfo.cs | 3 +-- 7 files changed, 7 insertions(+), 20 deletions(-) rename osu.Game/IO/Serialization/{IJsonSerializable.cs => JsonSerializableExtensions.cs} (76%) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 353636c8af..3eb766a667 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -10,7 +10,6 @@ using Newtonsoft.Json; using osu.Framework.Localisation; using osu.Framework.Testing; using osu.Game.Database; -using osu.Game.IO.Serialization; using osu.Game.Rulesets; using osu.Game.Scoring; @@ -18,7 +17,7 @@ namespace osu.Game.Beatmaps { [ExcludeFromDynamicCompile] [Serializable] - public class BeatmapInfo : IEquatable, IJsonSerializable, IHasPrimaryKey + public class BeatmapInfo : IEquatable, IHasPrimaryKey { public int ID { get; set; } diff --git a/osu.Game/Beatmaps/IBeatmap.cs b/osu.Game/Beatmaps/IBeatmap.cs index 769b33009a..f61dd269e1 100644 --- a/osu.Game/Beatmaps/IBeatmap.cs +++ b/osu.Game/Beatmaps/IBeatmap.cs @@ -4,12 +4,11 @@ using System.Collections.Generic; using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.Timing; -using osu.Game.IO.Serialization; using osu.Game.Rulesets.Objects; namespace osu.Game.Beatmaps { - public interface IBeatmap : IJsonSerializable + public interface IBeatmap { /// /// This beatmap's info. diff --git a/osu.Game/IO/Serialization/IJsonSerializable.cs b/osu.Game/IO/Serialization/JsonSerializableExtensions.cs similarity index 76% rename from osu.Game/IO/Serialization/IJsonSerializable.cs rename to osu.Game/IO/Serialization/JsonSerializableExtensions.cs index c8d5ce39a6..5b47d0bad1 100644 --- a/osu.Game/IO/Serialization/IJsonSerializable.cs +++ b/osu.Game/IO/Serialization/JsonSerializableExtensions.cs @@ -7,21 +7,14 @@ using osu.Framework.IO.Serialization; namespace osu.Game.IO.Serialization { - public interface IJsonSerializable - { - } - public static class JsonSerializableExtensions { - public static string Serialize(this IJsonSerializable obj) => JsonConvert.SerializeObject(obj, CreateGlobalSettings()); + public static string Serialize(this object obj) => JsonConvert.SerializeObject(obj, CreateGlobalSettings()); public static T Deserialize(this string objString) => JsonConvert.DeserializeObject(objString, CreateGlobalSettings()); public static void DeserializeInto(this string objString, T target) => JsonConvert.PopulateObject(objString, target, CreateGlobalSettings()); - /// - /// Creates the default that should be used for all s. - /// public static JsonSerializerSettings CreateGlobalSettings() => new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore, diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 9f3b5eaf5b..1199d8a956 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -11,7 +11,6 @@ using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Graphics.Sprites; using osu.Framework.Testing; using osu.Game.Configuration; -using osu.Game.IO.Serialization; using osu.Game.Rulesets.UI; using osu.Game.Utils; @@ -21,7 +20,7 @@ namespace osu.Game.Rulesets.Mods /// The base class for gameplay modifiers. /// [ExcludeFromDynamicCompile] - public abstract class Mod : IMod, IEquatable, IJsonSerializable, IDeepCloneable + public abstract class Mod : IMod, IEquatable, IDeepCloneable { /// /// The name of this mod. diff --git a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs index 4b3c3f90f0..dcd2cc8b55 100644 --- a/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs +++ b/osu.Game/Rulesets/Timing/MultiplierControlPoint.cs @@ -3,14 +3,13 @@ using System; using osu.Game.Beatmaps.ControlPoints; -using osu.Game.IO.Serialization; namespace osu.Game.Rulesets.Timing { /// /// A control point which adds an aggregated multiplier based on the provided 's BeatLength and 's SpeedMultiplier. /// - public class MultiplierControlPoint : IJsonSerializable, IComparable + public class MultiplierControlPoint : IComparable { /// /// The time in milliseconds at which this starts. diff --git a/osu.Game/Screens/Edit/ClipboardContent.cs b/osu.Game/Screens/Edit/ClipboardContent.cs index b2edbedccc..0348a7c15d 100644 --- a/osu.Game/Screens/Edit/ClipboardContent.cs +++ b/osu.Game/Screens/Edit/ClipboardContent.cs @@ -4,13 +4,12 @@ using System.Collections.Generic; using System.Linq; using Newtonsoft.Json; -using osu.Game.IO.Serialization; using osu.Game.IO.Serialization.Converters; using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Edit { - public class ClipboardContent : IJsonSerializable + public class ClipboardContent { [JsonConverter(typeof(TypedListConverter))] public IList HitObjects; diff --git a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs index b64e5ca98f..a2b84c79af 100644 --- a/osu.Game/Screens/Play/HUD/SkinnableInfo.cs +++ b/osu.Game/Screens/Play/HUD/SkinnableInfo.cs @@ -8,7 +8,6 @@ using Newtonsoft.Json; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Extensions; -using osu.Game.IO.Serialization; using osu.Game.Skinning; using osuTK; @@ -18,7 +17,7 @@ namespace osu.Game.Screens.Play.HUD /// Serialised information governing custom changes to an . /// [Serializable] - public class SkinnableInfo : IJsonSerializable + public class SkinnableInfo { public Type Type { get; set; } From eb21ed08f89a06b76de8b45a45886d80365bf9c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 14:51:14 +0900 Subject: [PATCH 724/961] Update test to only compare `HitObject`s --- .../Formats/LegacyBeatmapEncoderTest.cs | 72 +++++++++++-------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs index 85b8a3d190..896aa53f82 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapEncoderTest.cs @@ -66,6 +66,47 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); } + [TestCaseSource(nameof(allBeatmaps))] + public void TestEncodeDecodeStabilityWithNonLegacyControlPoints(string name) + { + var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name); + + // we are testing that the transfer of relevant data to hitobjects (from legacy control points) sticks through encode/decode. + // before the encode step, the legacy information is removed here. + decoded.beatmap.ControlPointInfo = removeLegacyControlPointTypes(decoded.beatmap.ControlPointInfo); + + var decodedAfterEncode = decodeFromLegacy(encodeToLegacy(decoded), name); + + // in this process, we may lose some detail in the control points section. + // let's focus on only the hitobjects. + var originalHitObjects = decoded.beatmap.HitObjects.Serialize(); + var newHitObjects = decodedAfterEncode.beatmap.HitObjects.Serialize(); + + Assert.That(newHitObjects, Is.EqualTo(originalHitObjects)); + + ControlPointInfo removeLegacyControlPointTypes(ControlPointInfo controlPointInfo) + { + // emulate non-legacy control points by cloning the non-legacy portion. + // the assertion is that the encoder can recreate this losslessly from hitobject data. + Assert.IsInstanceOf(controlPointInfo); + + var newControlPoints = new ControlPointInfo(); + + foreach (var point in controlPointInfo.AllControlPoints) + { + // completely ignore "legacy" types, which have been moved to HitObjects. + // even though these would mostly be ignored by the Add call, they will still be available in groups, + // which isn't what we want to be testing here. + if (point is SampleControlPoint) + continue; + + newControlPoints.Add(point.Time, point.DeepClone()); + } + + return newControlPoints; + } + } + [Test] public void TestEncodeMultiSegmentSliderWithFloatingPointError() { @@ -93,37 +134,6 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.That(decodedSlider.Path.ControlPoints.Count, Is.EqualTo(5)); } - [TestCaseSource(nameof(allBeatmaps))] - public void TestEncodeDecodeStabilityWithNonLegacyControlPoints(string name) - { - var decoded = decodeFromLegacy(beatmaps_resource_store.GetStream(name), name); - - sort(decoded.beatmap); - - var originalSerialized = decoded.beatmap.Serialize(); - var encoded = encodeToLegacy(decoded); - - Assert.AreEqual(typeof(LegacyControlPointInfo), decoded.beatmap.ControlPointInfo.GetType()); - - // emulate non-legacy control points by cloning the non-legacy portion. - // the assertion is that the encoder can recreate this losslessly from hitobject data. - var controlPointInfo = new ControlPointInfo(); - - foreach (var point in decoded.beatmap.ControlPointInfo.AllControlPoints) - controlPointInfo.Add(point.Time, point.DeepClone()); - - decoded.beatmap.ControlPointInfo = controlPointInfo; - - Assert.AreNotEqual(typeof(LegacyControlPointInfo), decoded.beatmap.ControlPointInfo.GetType()); - - var decodedAfterEncode = decodeFromLegacy(encoded, name); - - sort(decodedAfterEncode.beatmap); - - Assert.That(decodedAfterEncode.beatmap.Serialize(), Is.EqualTo(originalSerialized)); - Assert.IsTrue(areComboColoursEqual(decodedAfterEncode.beatmapSkin.Configuration, decoded.beatmapSkin.Configuration)); - } - private bool areComboColoursEqual(IHasComboColours a, IHasComboColours b) { // equal to null, no need to SequenceEqual From 9fa8bee094cb24fe5656193d0d60a5b5172c6844 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 14:51:19 +0900 Subject: [PATCH 725/961] Remove outdated TODO --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 461611da3b..75d9a56f3e 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -172,7 +172,7 @@ namespace osu.Game.Beatmaps.Formats writer.WriteLine("[TimingPoints]"); - if (!(beatmap.ControlPointInfo is LegacyControlPointInfo)) // todo: always run this? probably no harm. + if (!(beatmap.ControlPointInfo is LegacyControlPointInfo)) { var legacyControlPoints = new LegacyControlPointInfo(); From 448c58c35d0aec96e9a3c91323f69564ddcb8c89 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 15:08:07 +0900 Subject: [PATCH 726/961] Remove unnecessary variable discard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs index 5152549bed..ff0ca5ebe1 100644 --- a/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs +++ b/osu.Game/Beatmaps/Legacy/LegacyControlPointInfo.cs @@ -34,7 +34,7 @@ namespace osu.Game.Beatmaps.Legacy protected override bool CheckAlreadyExisting(double time, ControlPoint newPoint) { - if (newPoint is SampleControlPoint _) + if (newPoint is SampleControlPoint) { var existing = BinarySearch(SamplePoints, time); return newPoint.IsRedundant(existing); From d988aa168001290604dcb0f1951886b5012c55ee Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 15:05:10 +0900 Subject: [PATCH 727/961] Actually serialise `SampleControlPoint`s along with `HitObject`s --- osu.Game/Beatmaps/ControlPoints/ControlPoint.cs | 2 ++ osu.Game/Rulesets/Objects/HitObject.cs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs index 643c5d9adb..8203f2e968 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPoint.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using Newtonsoft.Json; using osu.Game.Graphics; using osu.Game.Utils; using osuTK.Graphics; @@ -13,6 +14,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The time at which the control point takes effect. /// + [JsonIgnore] public double Time => controlPointGroup?.Time ?? 0; private ControlPointGroup controlPointGroup; diff --git a/osu.Game/Rulesets/Objects/HitObject.cs b/osu.Game/Rulesets/Objects/HitObject.cs index fb1b6cd267..c4b9e6e1ad 100644 --- a/osu.Game/Rulesets/Objects/HitObject.cs +++ b/osu.Game/Rulesets/Objects/HitObject.cs @@ -66,7 +66,6 @@ namespace osu.Game.Rulesets.Objects } } - [JsonIgnore] public SampleControlPoint SampleControlPoint; /// From a2546243737d3b4d9f4f10f8af215a4e42645fb1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 17:18:04 +0900 Subject: [PATCH 728/961] Avoid performing beatmap metadata lookups when entering the editor If none of the lookup parameters are available, skip the lookup completely. --- osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs index 7824205257..6ae7f7481e 100644 --- a/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs +++ b/osu.Game/Beatmaps/BeatmapManager_BeatmapOnlineLookupQueue.cs @@ -153,6 +153,11 @@ namespace osu.Game.Beatmaps if (!storage.Exists(cache_database_name)) return false; + if (string.IsNullOrEmpty(beatmap.MD5Hash) + && string.IsNullOrEmpty(beatmap.Path) + && beatmap.OnlineBeatmapID == null) + return false; + try { using (var db = new SqliteConnection(storage.GetDatabaseConnectionString("online"))) From 90768a86a65db383aa2de2d58756c2a59bc80139 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Aug 2021 17:55:13 +0900 Subject: [PATCH 729/961] Adjust classic scoring as a constant multiple over standardised scoring --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 16f2607bad..3073ec9340 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -226,8 +226,9 @@ namespace osu.Game.Rulesets.Scoring return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)) * scoreMultiplier; case ScoringMode.Classic: - // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) - return getBonusScore(statistics) + (accuracyRatio * Math.Max(1, maxCombo) * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25); + // This feels very similar to osu!stable scoring (ScoreV1) while maintaining that classic scoring is only a constant multiple of standardised scoring. + // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two systems. + return GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score * Math.Pow(maxCombo, 2) * 25; } } From bfcadcc4ac591b8128e26ff80083c478075e367f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Aug 2021 18:56:26 +0900 Subject: [PATCH 730/961] Revert some changes --- osu.Game/Online/Leaderboards/Leaderboard.cs | 5 -- .../Online/Leaderboards/LeaderboardScore.cs | 2 +- .../Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- .../BeatmapSet/Scores/ScoresContainer.cs | 72 ++++++++----------- osu.Game/Screens/Ranking/ScorePanelList.cs | 17 +---- 5 files changed, 32 insertions(+), 66 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index f3a06994ee..1d9d2e6b14 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -19,7 +19,6 @@ using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Placeholders; -using osu.Game.Rulesets.Scoring; using osuTK; using osuTK.Graphics; @@ -29,7 +28,6 @@ namespace osu.Game.Online.Leaderboards { private const double fade_duration = 300; - private readonly Bindable scoringMode = new Bindable(); private readonly OsuScrollContainer scrollContainer; private readonly Container placeholderContainer; private readonly UserTopScoreContainer topScoreContainer; @@ -255,9 +253,6 @@ namespace osu.Game.Online.Leaderboards apiState.BindTo(api.State); apiState.BindValueChanged(onlineStateChanged, true); - - configManager.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); - scoringMode.BindValueChanged(_ => RefreshScores(), true); } private APIRequest getScoresRequest; diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 206b0e7936..9a0bc35bb3 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -199,7 +199,7 @@ namespace osu.Game.Online.Leaderboards TextColour = Color4.White, GlowColour = Color4Extensions.FromHex(@"83ccfa"), Font = OsuFont.Numeric.With(size: 23), - Text = scoreManager.GetTotalScore(score).ToLocalisableString(@"N0"), + Current = scoreManager.GetBindableTotalScoreString(score) }, RankContainer = new Container { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 847df53edc..9497ed9d35 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -152,7 +152,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores { Margin = new MarginPadding { Right = horizontal_inset }, Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium), - Text = scoreManager.GetTotalScore(score).ToLocalisableString(@"N0"), + Current = scoreManager.GetBindableTotalScoreString(score), }, new OsuSpriteText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 91c3dfad65..1b7e152c07 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -15,7 +15,6 @@ using osu.Framework.Bindables; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; -using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; using osu.Game.Users; @@ -30,7 +29,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private readonly Bindable ruleset = new Bindable(); private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global); private readonly IBindable user = new Bindable(); - private readonly Bindable scoringMode = new Bindable(); private readonly Box background; private readonly ScoreTable scoreTable; @@ -51,15 +49,37 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private GetScoresRequest getScoresRequest; - private APILegacyScores scores; - protected APILegacyScores Scores { - set + set => Schedule(() => { - scores = value; - displayScores(value); - } + topScoresContainer.Clear(); + + if (value?.Scores.Any() != true) + { + scoreTable.ClearScores(); + scoreTable.Hide(); + return; + } + + var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)) + .OrderByDescending(s => scoreManager.GetTotalScore(s)) + .ThenBy(s => s.OnlineScoreID) + .ToList(); + + var topScore = scoreInfos.First(); + + scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); + scoreTable.Show(); + + var userScore = value.UserScore; + var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); + + topScoresContainer.Add(new DrawableTopScore(topScore)); + + if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); + }); } public ScoresContainer() @@ -160,7 +180,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores background.Colour = colourProvider.Background5; user.BindTo(api.LocalUser); - config.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); } protected override void LoadComplete() @@ -173,8 +192,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores Beatmap.BindValueChanged(onBeatmapChanged); user.BindValueChanged(onUserChanged, true); - - scoringMode.BindValueChanged(_ => displayScores(scores)); } private void onBeatmapChanged(ValueChangedEvent beatmap) @@ -246,39 +263,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores api.Queue(getScoresRequest); } - private void displayScores(APILegacyScores newScores) - { - Schedule(() => - { - topScoresContainer.Clear(); - - if (newScores?.Scores.Any() != true) - { - scoreTable.ClearScores(); - scoreTable.Hide(); - return; - } - - var scoreInfos = newScores.Scores.Select(s => s.CreateScoreInfo(rulesets)) - .OrderByDescending(s => scoreManager.GetTotalScore(s)) - .ThenBy(s => s.OnlineScoreID) - .ToList(); - - var topScore = scoreInfos.First(); - - scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); - scoreTable.Show(); - - var userScore = newScores.UserScore; - var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); - - topScoresContainer.Add(new DrawableTopScore(topScore)); - - if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); - }); - } - private bool userIsSupporter => api.IsLoggedIn && api.LocalUser.Value.IsSupporter; } } diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index c9ddfd27d3..ba90585ab5 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -10,9 +10,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; -using osu.Game.Configuration; using osu.Game.Graphics.Containers; -using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osuTK; using osuTK.Input; @@ -292,26 +290,15 @@ namespace osu.Game.Screens.Ranking { public override IEnumerable FlowingChildren => applySorting(AliveInternalChildren); - private readonly Bindable scoringMode = new Bindable(); - [Resolved] private ScoreManager scoreManager { get; set; } - [BackgroundDependencyLoader] - private void load(OsuConfigManager configManager) - { - configManager.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); - } - protected override void LoadComplete() { base.LoadComplete(); - scoringMode.BindValueChanged(mode => - { - foreach (var c in Children) - SetLayoutPosition(c, scoreManager.GetTotalScore(c.Panel.Score)); - }, true); + foreach (var c in Children) + SetLayoutPosition(c, scoreManager.GetTotalScore(c.Panel.Score)); } public int GetPanelIndex(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Panel.Score != score).Count(); From 3f93aa15079c6f593d2ad436e09e8536bf074a84 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 31 Aug 2021 20:12:40 +0900 Subject: [PATCH 731/961] Fix traceable sliders incorrectly being opaque Closes https://github.com/ppy/osu/issues/14449. Regressed in https://github.com/ppy/osu/pull/14205. --- .../Skinning/Legacy/LegacySliderBody.cs | 2 -- .../Legacy/OsuLegacySkinTransformer.cs | 21 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index 1c8dfeac52..7d69e5ecdc 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -22,8 +22,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy // Roughly matches osu!stable's slider border portions. => base.CalculatedBorderPortion * 0.77f; - public new Color4 AccentColour => new Color4(base.AccentColour.R, base.AccentColour.G, base.AccentColour.B, 0.7f); - protected override Color4 ColourAt(float position) { float realBorderPortion = shadow_portion + CalculatedBorderPortion; diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 41b0a88f11..16c770706d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -3,9 +3,11 @@ using System; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { @@ -118,8 +120,23 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { switch (lookup) { - case OsuSkinColour colour: - return base.GetConfig(new SkinCustomColourLookup(colour)); + case OsuSkinColour colourLookup: + var colour = base.GetConfig(new SkinCustomColourLookup(colourLookup)); + + if (colour == null) + return null; + + switch (colourLookup) + { + case OsuSkinColour.SliderTrackOverride: + var bindableColour = ((Bindable)colour); + + // legacy skins use a constant value for slider track alpha, regardless of the source colour. + bindableColour.Value = bindableColour.Value.Opacity(0.7f); + break; + } + + return colour; case OsuSkinConfiguration osuLookup: switch (osuLookup) From cfcf3d7507b8b80b89d082e3027d354bcffa5220 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Aug 2021 20:43:50 +0900 Subject: [PATCH 732/961] Use synchronous total score retrieval for bindable --- osu.Game/Scoring/ScoreManager.cs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index f310462d6e..8cf1c85956 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -195,9 +195,6 @@ namespace osu.Game.Scoring { public readonly Bindable ScoringMode = new Bindable(); - private readonly ScoreInfo score; - private readonly ScoreManager scoreManager; - /// /// Creates a new . /// @@ -205,20 +202,7 @@ namespace osu.Game.Scoring /// The . public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager) { - this.score = score; - this.scoreManager = scoreManager; - - ScoringMode.BindValueChanged(onScoringModeChanged, true); - } - - private CancellationTokenSource difficultyCancellationSource; - - private void onScoringModeChanged(ValueChangedEvent mode) - { - difficultyCancellationSource?.Cancel(); - difficultyCancellationSource = new CancellationTokenSource(); - - scoreManager.GetTotalScoreAsync(score, difficultyCancellationSource.Token).ContinueWith(s => Value = s.Result, TaskContinuationOptions.OnlyOnRanToCompletion); + ScoringMode.BindValueChanged(_ => Value = scoreManager.GetTotalScore(score), true); } } From fee94236de92815f9d9b29375b56c5b7604ec132 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Aug 2021 21:36:31 +0900 Subject: [PATCH 733/961] Fix update-thread pauses --- .../BeatmapSet/Scores/ScoresContainer.cs | 39 +++++++----- osu.Game/Scoring/ScoreManager.cs | 19 ++++++ osu.Game/Screens/Ranking/ScorePanelList.cs | 62 +++++++++++-------- .../Select/Leaderboards/BeatmapLeaderboard.cs | 30 ++++++--- 4 files changed, 99 insertions(+), 51 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 1b7e152c07..8e9a9eb684 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osuTK; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Game.Online.API.Requests.Responses; using osu.Game.Beatmaps; using osu.Game.Online.API; @@ -49,36 +51,41 @@ namespace osu.Game.Overlays.BeatmapSet.Scores private GetScoresRequest getScoresRequest; + private CancellationTokenSource loadCancellationSource; + protected APILegacyScores Scores { set => Schedule(() => { + loadCancellationSource?.Cancel(); + loadCancellationSource = new CancellationTokenSource(); + topScoresContainer.Clear(); + scoreTable.ClearScores(); + scoreTable.Hide(); if (value?.Scores.Any() != true) - { - scoreTable.ClearScores(); - scoreTable.Hide(); return; - } - var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)) - .OrderByDescending(s => scoreManager.GetTotalScore(s)) - .ThenBy(s => s.OnlineScoreID) - .ToList(); + scoreManager.GetOrderedScoresAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) + .ContinueWith(ordered => Schedule(() => + { + if (loadCancellationSource.IsCancellationRequested) + return; - var topScore = scoreInfos.First(); + var topScore = ordered.Result.First(); - scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); - scoreTable.Show(); + scoreTable.DisplayScores(ordered.Result, topScore.Beatmap?.Status.GrantsPerformancePoints() == true); + scoreTable.Show(); - var userScore = value.UserScore; - var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); + var userScore = value.UserScore; + var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); - topScoresContainer.Add(new DrawableTopScore(topScore)); + topScoresContainer.Add(new DrawableTopScore(topScore)); - if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) - topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); + if (userScoreInfo != null && userScoreInfo.OnlineScoreID != topScore.OnlineScoreID) + topScoresContainer.Add(new DrawableTopScore(userScoreInfo, userScore.Position)); + }), TaskContinuationOptions.OnlyOnRanToCompletion); }); } diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 8cf1c85956..71edc65fcc 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -106,6 +106,25 @@ namespace osu.Game.Scoring => base.CheckLocalAvailability(model, items) || (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID)); + public async Task GetOrderedScoresAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) + { + var difficultyCache = difficulties?.Invoke(); + + if (difficultyCache == null) + return orderByTotalScore(scores); + + // Compute difficulties asynchronously first to prevent blocks on the main thread. + foreach (var s in scores) + { + await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + } + + return orderByTotalScore(scores); + + ScoreInfo[] orderByTotalScore(IEnumerable incoming) => incoming.OrderByDescending(GetTotalScore).ThenBy(s => s.OnlineScoreID).ToArray(); + } + /// /// Retrieves a bindable that represents the total score of a . /// diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index ba90585ab5..e319e824a1 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -61,6 +62,10 @@ namespace osu.Game.Screens.Ranking public readonly Bindable SelectedScore = new Bindable(); + [Resolved] + private ScoreManager scoreManager { get; set; } + + private readonly CancellationTokenSource loadCancellationSource = new CancellationTokenSource(); private readonly Flow flow; private readonly Scroll scroll; private ScorePanel expandedPanel; @@ -115,32 +120,33 @@ namespace osu.Game.Screens.Ranking }; }); - flow.Add(panel.CreateTrackingContainer().With(d => - { - d.Anchor = Anchor.Centre; - d.Origin = Anchor.Centre; - })); + scoreManager.GetOrderedScoresAsync(new[] { score }) + .ContinueWith(_ => Schedule(() => + { + flow.Add(panel.CreateTrackingContainer().With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + })); - if (IsLoaded) - { - if (SelectedScore.Value == score) - { - SelectedScore.TriggerChange(); - } - else - { - // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. - // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. - if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) - { - // A somewhat hacky property is used here because we need to: - // 1) Scroll after the scroll container's visible range is updated. - // 2) Scroll before the scroll container's scroll position is updated. - // Without this, we would have a 1-frame positioning error which looks very jarring. - scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; - } - } - } + if (SelectedScore.Value == score) + { + SelectedScore.TriggerChange(); + } + else + { + // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. + // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. + if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + { + // A somewhat hacky property is used here because we need to: + // 1) Scroll after the scroll container's visible range is updated. + // 2) Scroll before the scroll container's scroll position is updated. + // Without this, we would have a 1-frame positioning error which looks very jarring. + scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + } + } + })); return panel; } @@ -286,6 +292,12 @@ namespace osu.Game.Screens.Ranking return base.OnKeyDown(e); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + loadCancellationSource?.Cancel(); + } + private class Flow : FillFlowContainer { public override IEnumerable FlowingChildren => applySorting(AliveInternalChildren); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 0276ae8b2a..54ec42127d 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Beatmaps; @@ -66,6 +68,9 @@ namespace osu.Game.Screens.Select.Leaderboards [Resolved] private ScoreManager scoreManager { get; set; } + [Resolved] + private BeatmapDifficultyCache difficultyCache { get; set; } + [Resolved] private IBindable ruleset { get; set; } @@ -120,8 +125,13 @@ namespace osu.Game.Screens.Select.Leaderboards protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; + private CancellationTokenSource loadCancellationSource; + protected override APIRequest FetchScores(Action> scoresCallback) { + loadCancellationSource?.Cancel(); + loadCancellationSource = new CancellationTokenSource(); + if (Beatmap == null) { PlaceholderState = PlaceholderState.NoneSelected; @@ -146,11 +156,8 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); } - Scores = scores.OrderByDescending(s => scoreManager.GetTotalScore(s)) - .ThenBy(s => s.OnlineScoreID) - .ToArray(); - - PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; + scoreManager.GetOrderedScoresAsync(scores.ToArray(), loadCancellationSource.Token) + .ContinueWith(ordered => scoresCallback?.Invoke(ordered.Result), TaskContinuationOptions.OnlyOnRanToCompletion); return null; } @@ -185,12 +192,15 @@ namespace osu.Game.Screens.Select.Leaderboards req.Success += r => { - scoresCallback?.Invoke( - r.Scores.Select(s => s.CreateScoreInfo(rulesets)) - .OrderByDescending(s => scoreManager.GetTotalScore(s)) - .ThenBy(s => s.OnlineScoreID)); + scoreManager.GetOrderedScoresAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) + .ContinueWith(ordered => Schedule(() => + { + if (loadCancellationSource.IsCancellationRequested) + return; - TopScore = r.UserScore?.CreateScoreInfo(rulesets); + scoresCallback?.Invoke(ordered.Result); + TopScore = r.UserScore?.CreateScoreInfo(rulesets); + }), TaskContinuationOptions.OnlyOnRanToCompletion); }; return req; From 999386da2919a022132970344a2d089f192c9d2c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 31 Aug 2021 21:47:49 +0900 Subject: [PATCH 734/961] Cleanup --- osu.Game/Online/Leaderboards/Leaderboard.cs | 3 +-- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 2 +- osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs | 2 +- osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 1d9d2e6b14..4f8b27602b 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Threading; -using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; @@ -247,7 +246,7 @@ namespace osu.Game.Online.Leaderboards private readonly IBindable apiState = new Bindable(); [BackgroundDependencyLoader] - private void load(OsuConfigManager configManager) + private void load() { if (api != null) apiState.BindTo(api.State); diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 9a0bc35bb3..934b905a1a 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -198,8 +198,8 @@ namespace osu.Game.Online.Leaderboards { TextColour = Color4.White, GlowColour = Color4Extensions.FromHex(@"83ccfa"), + Current = scoreManager.GetBindableTotalScoreString(score), Font = OsuFont.Numeric.With(size: 23), - Current = scoreManager.GetBindableTotalScoreString(score) }, RankContainer = new Container { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs index 9497ed9d35..a154016824 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs @@ -151,8 +151,8 @@ namespace osu.Game.Overlays.BeatmapSet.Scores new OsuSpriteText { Margin = new MarginPadding { Right = horizontal_inset }, - Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium), Current = scoreManager.GetBindableTotalScoreString(score), + Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium) }, new OsuSpriteText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index 8e9a9eb684..a5a373467e 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -182,7 +182,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider, OsuConfigManager config) + private void load(OverlayColourProvider colourProvider) { background.Colour = colourProvider.Background5; From 79f71e5181eb5410090769117175a03f094a265e Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 31 Aug 2021 13:56:44 +0100 Subject: [PATCH 735/961] get user id when importing scores --- osu.Game/Scoring/ScoreManager.cs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 83bcac01ac..4cfcc00bb8 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring.Legacy; +using osu.Game.Users; namespace osu.Game.Scoring { @@ -43,6 +44,8 @@ namespace osu.Game.Scoring [CanBeNull] private readonly OsuConfigManager configManager; + private IAPIProvider api { get; set; } + public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null, Func difficulties = null, OsuConfigManager configManager = null) : base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost) @@ -51,6 +54,7 @@ namespace osu.Game.Scoring this.beatmaps = beatmaps; this.difficulties = difficulties; this.configManager = configManager; + this.api = api; } protected override ScoreInfo CreateModel(ArchiveReader archive) @@ -72,8 +76,31 @@ namespace osu.Game.Scoring } } + private Dictionary previouslyLookedUpUsernames = new Dictionary(); + protected override Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) - => Task.CompletedTask; + { + // These scores only provide the user's username but we need the user's ID too. + if (model.UserID <= 1 && model.UserString != null) + { + if (previouslyLookedUpUsernames.TryGetValue(model.UserString, out User user)) + { + model.UserID = user.Id; + return Task.CompletedTask; + } + + var request = new GetUserRequest(model.UserString); + request.Success += user => + { + model.UserID = user.Id; + previouslyLookedUpUsernames.TryAdd(model.UserString, user); + }; + + api.Queue(request); + } + + return Task.CompletedTask; + } protected override void ExportModelTo(ScoreInfo model, Stream outputStream) { From 0a87b461d70ad61e423675d45f04e253bae73259 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 31 Aug 2021 14:11:37 +0100 Subject: [PATCH 736/961] fix code quality issues --- osu.Game/Scoring/ScoreManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 4cfcc00bb8..d5d33283b3 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -76,7 +76,7 @@ namespace osu.Game.Scoring } } - private Dictionary previouslyLookedUpUsernames = new Dictionary(); + private readonly Dictionary previouslyLookedUpUsernames = new Dictionary(); protected override Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) { @@ -90,10 +90,10 @@ namespace osu.Game.Scoring } var request = new GetUserRequest(model.UserString); - request.Success += user => + request.Success += u => { - model.UserID = user.Id; - previouslyLookedUpUsernames.TryAdd(model.UserString, user); + model.UserID = u.Id; + previouslyLookedUpUsernames.TryAdd(model.UserString, u); }; api.Queue(request); From 9288ca1191dfbbcf0099ff749890580cc050e27f Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 31 Aug 2021 14:34:45 +0100 Subject: [PATCH 737/961] handle api is null --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index d5d33283b3..3c99dd6637 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -96,7 +96,7 @@ namespace osu.Game.Scoring previouslyLookedUpUsernames.TryAdd(model.UserString, u); }; - api.Queue(request); + api?.Queue(request); } return Task.CompletedTask; From a190801291d79d42115f8ed03805109228cda21e Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 19:36:27 +0300 Subject: [PATCH 738/961] Revert no longer required tooltip content changes --- osu.Game/Overlays/Mods/LocalPlayerModButton.cs | 3 +-- osu.Game/Overlays/Mods/ModButton.cs | 6 +++--- osu.Game/Overlays/Mods/ModButtonTooltip.cs | 10 ++++------ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs index 1d5ddfcf06..d26bbf344d 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs +++ b/osu.Game/Overlays/Mods/LocalPlayerModButton.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; @@ -66,7 +65,7 @@ namespace osu.Game.Overlays.Mods incompatibleIcon.Hide(); } - public override ITooltip GetCustomTooltip() => new LocalPlayerModButtonTooltip(); + public override ITooltip GetCustomTooltip() => new LocalPlayerModButtonTooltip(); private class LocalPlayerModButtonTooltip : ModButtonTooltip { diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index cc8acb7513..979e2c8da3 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Mods /// /// Represents a clickable button which can cycle through one of more mods. /// - public class ModButton : ModButtonEmpty, IHasCustomTooltip + public class ModButton : ModButtonEmpty, IHasCustomTooltip { private ModIcon foregroundIcon; private ModIcon backgroundIcon; @@ -312,8 +312,8 @@ namespace osu.Game.Overlays.Mods Mod = mod; } - public virtual ITooltip GetCustomTooltip() => new ModButtonTooltip(); + public virtual ITooltip GetCustomTooltip() => new ModButtonTooltip(); - public object TooltipContent => this; + public Mod TooltipContent => SelectedMod ?? Mods.FirstOrDefault(); } } diff --git a/osu.Game/Overlays/Mods/ModButtonTooltip.cs b/osu.Game/Overlays/Mods/ModButtonTooltip.cs index 0ad479670b..2f50e38a5a 100644 --- a/osu.Game/Overlays/Mods/ModButtonTooltip.cs +++ b/osu.Game/Overlays/Mods/ModButtonTooltip.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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -14,7 +13,7 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class ModButtonTooltip : VisibilityContainer, ITooltip + public class ModButtonTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText descriptionText; private readonly Box background; @@ -61,11 +60,10 @@ namespace osu.Game.Overlays.Mods private Mod lastMod; - public virtual void SetContent(ModButton button) + public void SetContent(Mod mod) { - var mod = button.SelectedMod ?? button.Mods.First(); - - if (mod.Equals(lastMod)) return; + if (mod.Equals(lastMod)) + return; lastMod = mod; From 208f66cc76ee102be8ae06397e11c7af4f894f89 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 Aug 2021 19:11:44 +0300 Subject: [PATCH 739/961] Simplify user graph tooltips logic The same tooltip can be used for the rank graph, the play history graph, and the replay history graph. The only difference between those three is the displayed label, which has now been included as part of the `TooltipContent`, rather than unnecessarily recreating tooltips just for different sprite texts. --- .../Profile/Header/Components/RankGraph.cs | 33 ++------------- .../Sections/Historical/UserHistoryGraph.cs | 42 +++---------------- osu.Game/Overlays/Profile/UserGraph.cs | 36 ++++++++++------ 3 files changed, 32 insertions(+), 79 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 7ba8ae7c80..3312cb2c4f 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -8,7 +8,6 @@ using Humanizer; using osu.Framework.Bindables; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; @@ -61,40 +60,16 @@ namespace osu.Game.Overlays.Profile.Header.Components placeholder.FadeIn(FADE_DURATION, Easing.Out); } - protected override object GetTooltipContent(int index, int rank) + protected override UserGraphTooltipContent GetTooltipContent(int index, int rank) { var days = ranked_days - index + 1; - return new TooltipDisplayContent + return new UserGraphTooltipContent { - Rank = rank.ToLocalisableString("\\##,##0"), + Name = UsersStrings.ShowRankGlobalSimple, + Count = rank.ToLocalisableString("\\##,##0"), Time = days == 0 ? "now" : $"{"day".ToQuantity(days)} ago" }; } - - protected override UserGraphTooltip GetTooltip() => new RankGraphTooltip(); - - private class RankGraphTooltip : UserGraphTooltip - { - public RankGraphTooltip() - : base(UsersStrings.ShowRankGlobalSimple) - { - } - - public override void SetContent(object content) - { - if (!(content is TooltipDisplayContent info)) - return; - - Counter.Text = info.Rank; - BottomText.Text = info.Time; - } - } - - private class TooltipDisplayContent - { - public LocalisableString Rank; - public string Time; - } } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 85287d2325..d86e976e70 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -28,43 +28,11 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override float GetDataPointHeight(long playCount) => playCount; - protected override UserGraphTooltip GetTooltip() => new HistoryGraphTooltip(tooltipCounterName); - - protected override object GetTooltipContent(DateTime date, long playCount) + protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) => new UserGraphTooltipContent { - return new TooltipDisplayContent - { - Name = tooltipCounterName, - Count = playCount.ToLocalisableString("N0"), - Date = date.ToLocalisableString("MMMM yyyy") - }; - } - - protected class HistoryGraphTooltip : UserGraphTooltip - { - private readonly LocalisableString tooltipCounterName; - - public HistoryGraphTooltip(LocalisableString tooltipCounterName) - : base(tooltipCounterName) - { - this.tooltipCounterName = tooltipCounterName; - } - - public override void SetContent(object content) - { - if (!(content is TooltipDisplayContent info) || info.Name != tooltipCounterName) - return; - - Counter.Text = info.Count; - BottomText.Text = info.Date; - } - } - - private class TooltipDisplayContent - { - public LocalisableString Name; - public LocalisableString Count; - public LocalisableString Date; - } + Name = tooltipCounterName, + Count = playCount.ToLocalisableString("N0"), + Time = date.ToLocalisableString("MMMM yyyy") + }; } } diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index b88cc32ff7..502bbbe1a6 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Profile /// /// Type of data to be used for X-axis of the graph. /// Type of data to be used for Y-axis of the graph. - public abstract class UserGraph : Container, IHasCustomTooltip + public abstract class UserGraph : Container, IHasCustomTooltip { protected const float FADE_DURATION = 150; @@ -118,23 +118,21 @@ namespace osu.Game.Overlays.Profile protected virtual void ShowGraph() => graph.FadeIn(FADE_DURATION, Easing.Out); protected virtual void HideGraph() => graph.FadeOut(FADE_DURATION, Easing.Out); - public ITooltip GetCustomTooltip() => GetTooltip(); + public ITooltip GetCustomTooltip() => new UserGraphTooltip(); - protected abstract UserGraphTooltip GetTooltip(); - - public object TooltipContent + public UserGraphTooltipContent TooltipContent { get { if (data == null || hoveredIndex == -1) - return null; + return default; var (key, value) = data[hoveredIndex]; return GetTooltipContent(key, value); } } - protected abstract object GetTooltipContent(TKey key, TValue value); + protected abstract UserGraphTooltipContent GetTooltipContent(TKey key, TValue value); protected class UserLineGraph : LineGraph { @@ -207,12 +205,12 @@ namespace osu.Game.Overlays.Profile } } - protected abstract class UserGraphTooltip : VisibilityContainer, ITooltip + private class UserGraphTooltip : VisibilityContainer, ITooltip { - protected readonly OsuSpriteText Counter, BottomText; + protected readonly OsuSpriteText Label, Counter, BottomText; private readonly Box background; - protected UserGraphTooltip(LocalisableString tooltipCounterName) + public UserGraphTooltip() { AutoSizeAxes = Axes.Both; Masking = true; @@ -238,10 +236,9 @@ namespace osu.Game.Overlays.Profile Spacing = new Vector2(3, 0), Children = new Drawable[] { - new OsuSpriteText + Label = new OsuSpriteText { Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Text = tooltipCounterName }, Counter = new OsuSpriteText { @@ -268,7 +265,12 @@ namespace osu.Game.Overlays.Profile background.Colour = colours.Gray1; } - public abstract void SetContent(object content); + public void SetContent(UserGraphTooltipContent content) + { + Label.Text = content.Name; + Counter.Text = content.Count; + BottomText.Text = content.Time; + } private bool instantMove = true; @@ -292,4 +294,12 @@ namespace osu.Game.Overlays.Profile protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); } } + + public class UserGraphTooltipContent + { + // todo: change to init-only on C# 9 + public LocalisableString Name { get; set; } + public LocalisableString Count { get; set; } + public LocalisableString Time { get; set; } + } } From da7ff4b1601019a44c96f3ee0fcc0004d541d288 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Sat, 28 Aug 2021 19:09:37 +0300 Subject: [PATCH 740/961] Update remaining tooltip implementations to use generics --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 115 +---------------- .../Drawables/DifficultyIconTooltip.cs | 121 ++++++++++++++++++ osu.Game/Graphics/DrawableDate.cs | 6 +- .../Home/News/FeaturedNewsItemPanel.cs | 14 +- .../Dashboard/Home/News/NewsGroupItem.cs | 14 +- osu.Game/Overlays/News/NewsCard.cs | 12 +- 6 files changed, 144 insertions(+), 138 deletions(-) create mode 100644 osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 199f719893..cda4377780 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -16,7 +16,6 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osuTK; @@ -24,7 +23,7 @@ using osuTK.Graphics; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip + public class DifficultyIcon : CompositeDrawable, IHasCustomTooltip { private readonly Container iconContainer; @@ -127,9 +126,9 @@ namespace osu.Game.Beatmaps.Drawables difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); } - public ITooltip GetCustomTooltip() => new DifficultyIconTooltip(); + public ITooltip GetCustomTooltip() => new DifficultyIconTooltip(); - public object TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null; + public DifficultyIconTooltipContent TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null; private class DifficultyRetriever : Component { @@ -173,113 +172,5 @@ namespace osu.Game.Beatmaps.Drawables difficultyCancellation?.Cancel(); } } - - private class DifficultyIconTooltipContent - { - public readonly BeatmapInfo Beatmap; - public readonly IBindable Difficulty; - - public DifficultyIconTooltipContent(BeatmapInfo beatmap, IBindable difficulty) - { - Beatmap = beatmap; - Difficulty = difficulty; - } - } - - private class DifficultyIconTooltip : VisibilityContainer, ITooltip - { - private readonly OsuSpriteText difficultyName, starRating; - private readonly Box background; - private readonly FillFlowContainer difficultyFlow; - - public DifficultyIconTooltip() - { - AutoSizeAxes = Axes.Both; - Masking = true; - CornerRadius = 5; - - Children = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - AutoSizeDuration = 200, - AutoSizeEasing = Easing.OutQuint, - Direction = FillDirection.Vertical, - Padding = new MarginPadding(10), - Children = new Drawable[] - { - difficultyName = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold), - }, - difficultyFlow = new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Direction = FillDirection.Horizontal, - Children = new Drawable[] - { - starRating = new OsuSpriteText - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), - }, - new SpriteIcon - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Margin = new MarginPadding { Left = 4 }, - Icon = FontAwesome.Solid.Star, - Size = new Vector2(12), - }, - } - } - } - } - }; - } - - [Resolved] - private OsuColour colours { get; set; } - - [BackgroundDependencyLoader] - private void load() - { - background.Colour = colours.Gray3; - } - - private readonly IBindable starDifficulty = new Bindable(); - - public void SetContent(object content) - { - if (!(content is DifficultyIconTooltipContent iconContent)) - return; - - difficultyName.Text = iconContent.Beatmap.Version; - - starDifficulty.UnbindAll(); - starDifficulty.BindTo(iconContent.Difficulty); - starDifficulty.BindValueChanged(difficulty => - { - starRating.Text = $"{difficulty.NewValue.Stars:0.##}"; - difficultyFlow.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars); - }, true); - } - - public void Move(Vector2 pos) => Position = pos; - - protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); - - protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); - } } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs new file mode 100644 index 0000000000..5b05e39090 --- /dev/null +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -0,0 +1,121 @@ +// 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.Cursor; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osuTK; + +namespace osu.Game.Beatmaps.Drawables +{ + public class DifficultyIconTooltip : VisibilityContainer, ITooltip + { + private readonly OsuSpriteText difficultyName, starRating; + private readonly Box background; + private readonly FillFlowContainer difficultyFlow; + + public DifficultyIconTooltip() + { + AutoSizeAxes = Axes.Both; + Masking = true; + CornerRadius = 5; + + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + AutoSizeDuration = 200, + AutoSizeEasing = Easing.OutQuint, + Direction = FillDirection.Vertical, + Padding = new MarginPadding(10), + Children = new Drawable[] + { + difficultyName = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold), + }, + difficultyFlow = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + starRating = new OsuSpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular), + }, + new SpriteIcon + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Left = 4 }, + Icon = FontAwesome.Solid.Star, + Size = new Vector2(12), + }, + } + } + } + } + }; + } + + [Resolved] + private OsuColour colours { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + background.Colour = colours.Gray3; + } + + private readonly IBindable starDifficulty = new Bindable(); + + public void SetContent(DifficultyIconTooltipContent content) + { + difficultyName.Text = content.Beatmap.Version; + + starDifficulty.UnbindAll(); + starDifficulty.BindTo(content.Difficulty); + starDifficulty.BindValueChanged(difficulty => + { + starRating.Text = $"{difficulty.NewValue.Stars:0.##}"; + difficultyFlow.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars); + }, true); + } + + public void Move(Vector2 pos) => Position = pos; + + protected override void PopIn() => this.FadeIn(200, Easing.OutQuint); + + protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); + } + + public class DifficultyIconTooltipContent + { + public readonly BeatmapInfo Beatmap; + public readonly IBindable Difficulty; + + public DifficultyIconTooltipContent(BeatmapInfo beatmap, IBindable difficulty) + { + Beatmap = beatmap; + Difficulty = difficulty; + } + } +} diff --git a/osu.Game/Graphics/DrawableDate.cs b/osu.Game/Graphics/DrawableDate.cs index 259d9c8d6e..567a39b4f4 100644 --- a/osu.Game/Graphics/DrawableDate.cs +++ b/osu.Game/Graphics/DrawableDate.cs @@ -10,7 +10,7 @@ using osu.Game.Utils; namespace osu.Game.Graphics { - public class DrawableDate : OsuSpriteText, IHasCustomTooltip + public class DrawableDate : OsuSpriteText, IHasCustomTooltip { private DateTimeOffset date; @@ -75,8 +75,8 @@ namespace osu.Game.Graphics private void updateTime() => Text = Format(); - public ITooltip GetCustomTooltip() => new DateTooltip(); + public ITooltip GetCustomTooltip() => new DateTooltip(); - public object TooltipContent => Date; + public DateTimeOffset TooltipContent => Date; } } diff --git a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs index ee88469e2f..72a85bcb6c 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs @@ -140,17 +140,15 @@ namespace osu.Game.Overlays.Dashboard.Home.News } } - private class Date : CompositeDrawable, IHasCustomTooltip + private class Date : CompositeDrawable, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); + public ITooltip GetCustomTooltip() => new DateTooltip(); - public object TooltipContent => date; - - private readonly DateTimeOffset date; + public DateTimeOffset TooltipContent { get; } public Date(DateTimeOffset date) { - this.date = date; + TooltipContent = date; } [BackgroundDependencyLoader] @@ -174,7 +172,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Origin = Anchor.TopRight, Font = OsuFont.GetFont(weight: FontWeight.Bold), // using Bold since there is no 800 weight alternative Colour = colourProvider.Light1, - Text = $"{date:dd}" + Text = $"{TooltipContent:dd}" }, new TextFlowContainer(f => { @@ -185,7 +183,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, - Text = $"{date:MMM yyyy}" + Text = $"{TooltipContent:MMM yyyy}" } } }; diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs index dc4f3f8c92..a681536156 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs @@ -67,17 +67,15 @@ namespace osu.Game.Overlays.Dashboard.Home.News }; } - private class Date : CompositeDrawable, IHasCustomTooltip + private class Date : CompositeDrawable, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); + public ITooltip GetCustomTooltip() => new DateTooltip(); - public object TooltipContent => date; - - private readonly DateTimeOffset date; + public DateTimeOffset TooltipContent { get; } public Date(DateTimeOffset date) { - this.date = date; + TooltipContent = date; } [BackgroundDependencyLoader] @@ -100,12 +98,12 @@ namespace osu.Game.Overlays.Dashboard.Home.News Margin = new MarginPadding { Vertical = 5 } }; - textFlow.AddText($"{date:dd}", t => + textFlow.AddText($"{TooltipContent:dd}", t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); }); - textFlow.AddText($"{date: MMM}", t => + textFlow.AddText($"{TooltipContent: MMM}", t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular); }); diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index cc2fa7e1e1..aee0a50de9 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -123,17 +123,15 @@ namespace osu.Game.Overlays.News main.AddText(post.Author, t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)); } - private class DateContainer : CircularContainer, IHasCustomTooltip + private class DateContainer : CircularContainer, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); + public ITooltip GetCustomTooltip() => new DateTooltip(); - public object TooltipContent => date; - - private readonly DateTimeOffset date; + public DateTimeOffset TooltipContent { get; } public DateContainer(DateTimeOffset date) { - this.date = date; + TooltipContent = date; } [BackgroundDependencyLoader] @@ -150,7 +148,7 @@ namespace osu.Game.Overlays.News }, new OsuSpriteText { - Text = date.ToString("d MMM yyyy").ToUpper(), + Text = TooltipContent.ToString("d MMM yyyy").ToUpper(), Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), Margin = new MarginPadding { From 69c23a2371ea9f962981a671a710a763178ceee4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 20:06:34 +0300 Subject: [PATCH 741/961] Explicitly implement tooltips on date drawables to avoid "convert to auto-property" inspections --- .../Dashboard/Home/News/FeaturedNewsItemPanel.cs | 14 ++++++++------ .../Overlays/Dashboard/Home/News/NewsGroupItem.cs | 14 ++++++++------ osu.Game/Overlays/News/NewsCard.cs | 12 +++++++----- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs index 72a85bcb6c..0d166eb858 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/FeaturedNewsItemPanel.cs @@ -142,13 +142,11 @@ namespace osu.Game.Overlays.Dashboard.Home.News private class Date : CompositeDrawable, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); - - public DateTimeOffset TooltipContent { get; } + private readonly DateTimeOffset date; public Date(DateTimeOffset date) { - TooltipContent = date; + this.date = date; } [BackgroundDependencyLoader] @@ -172,7 +170,7 @@ namespace osu.Game.Overlays.Dashboard.Home.News Origin = Anchor.TopRight, Font = OsuFont.GetFont(weight: FontWeight.Bold), // using Bold since there is no 800 weight alternative Colour = colourProvider.Light1, - Text = $"{TooltipContent:dd}" + Text = $"{date:dd}" }, new TextFlowContainer(f => { @@ -183,11 +181,15 @@ namespace osu.Game.Overlays.Dashboard.Home.News Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, - Text = $"{TooltipContent:MMM yyyy}" + Text = $"{date:MMM yyyy}" } } }; } + + ITooltip IHasCustomTooltip.GetCustomTooltip() => new DateTooltip(); + + DateTimeOffset IHasCustomTooltip.TooltipContent => date; } } } diff --git a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs index a681536156..77cfbc90b0 100644 --- a/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs +++ b/osu.Game/Overlays/Dashboard/Home/News/NewsGroupItem.cs @@ -69,13 +69,11 @@ namespace osu.Game.Overlays.Dashboard.Home.News private class Date : CompositeDrawable, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); - - public DateTimeOffset TooltipContent { get; } + private readonly DateTimeOffset date; public Date(DateTimeOffset date) { - TooltipContent = date; + this.date = date; } [BackgroundDependencyLoader] @@ -98,16 +96,20 @@ namespace osu.Game.Overlays.Dashboard.Home.News Margin = new MarginPadding { Vertical = 5 } }; - textFlow.AddText($"{TooltipContent:dd}", t => + textFlow.AddText($"{date:dd}", t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold); }); - textFlow.AddText($"{TooltipContent: MMM}", t => + textFlow.AddText($"{date: MMM}", t => { t.Font = OsuFont.GetFont(size: 14, weight: FontWeight.Regular); }); } + + ITooltip IHasCustomTooltip.GetCustomTooltip() => new DateTooltip(); + + DateTimeOffset IHasCustomTooltip.TooltipContent => date; } } } diff --git a/osu.Game/Overlays/News/NewsCard.cs b/osu.Game/Overlays/News/NewsCard.cs index aee0a50de9..68d0704825 100644 --- a/osu.Game/Overlays/News/NewsCard.cs +++ b/osu.Game/Overlays/News/NewsCard.cs @@ -125,13 +125,11 @@ namespace osu.Game.Overlays.News private class DateContainer : CircularContainer, IHasCustomTooltip { - public ITooltip GetCustomTooltip() => new DateTooltip(); - - public DateTimeOffset TooltipContent { get; } + private readonly DateTimeOffset date; public DateContainer(DateTimeOffset date) { - TooltipContent = date; + this.date = date; } [BackgroundDependencyLoader] @@ -148,7 +146,7 @@ namespace osu.Game.Overlays.News }, new OsuSpriteText { - Text = TooltipContent.ToString("d MMM yyyy").ToUpper(), + Text = date.ToString("d MMM yyyy").ToUpper(), Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), Margin = new MarginPadding { @@ -160,6 +158,10 @@ namespace osu.Game.Overlays.News } protected override bool OnClick(ClickEvent e) => true; // Protects the NewsCard from clicks while hovering DateContainer + + ITooltip IHasCustomTooltip.GetCustomTooltip() => new DateTooltip(); + + DateTimeOffset IHasCustomTooltip.TooltipContent => date; } } } From 3969350c9a38bd8ccf1408656c08dd280dbf0ec6 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 20:45:32 +0300 Subject: [PATCH 742/961] Convert to `readonly struct` and replace with constructor temporarily --- .../Profile/Header/Components/RankGraph.cs | 10 ++++------ .../Sections/Historical/UserHistoryGraph.cs | 11 ++++++----- osu.Game/Overlays/Profile/UserGraph.cs | 17 ++++++++++++----- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs index 3312cb2c4f..ca5f26e375 100644 --- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs +++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs @@ -64,12 +64,10 @@ namespace osu.Game.Overlays.Profile.Header.Components { var days = ranked_days - index + 1; - return new UserGraphTooltipContent - { - Name = UsersStrings.ShowRankGlobalSimple, - Count = rank.ToLocalisableString("\\##,##0"), - Time = days == 0 ? "now" : $"{"day".ToQuantity(days)} ago" - }; + return new UserGraphTooltipContent( + UsersStrings.ShowRankGlobalSimple, + rank.ToLocalisableString("\\##,##0"), + days == 0 ? "now" : $"{"day".ToQuantity(days)} ago"); } } } diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index d86e976e70..738edb9310 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -28,11 +28,12 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override float GetDataPointHeight(long playCount) => playCount; - protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) => new UserGraphTooltipContent + protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) { - Name = tooltipCounterName, - Count = playCount.ToLocalisableString("N0"), - Time = date.ToLocalisableString("MMMM yyyy") - }; + return new UserGraphTooltipContent( + tooltipCounterName, + playCount.ToLocalisableString("N0"), + date.ToLocalisableString("MMMM yyyy")); + } } } diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index 502bbbe1a6..f305e3afc3 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -295,11 +295,18 @@ namespace osu.Game.Overlays.Profile } } - public class UserGraphTooltipContent + public readonly struct UserGraphTooltipContent { - // todo: change to init-only on C# 9 - public LocalisableString Name { get; set; } - public LocalisableString Count { get; set; } - public LocalisableString Time { get; set; } + // todo: could use init-only properties on C# 9 which read better than a constructor. + public LocalisableString Name { get; } + public LocalisableString Count { get; } + public LocalisableString Time { get; } + + public UserGraphTooltipContent(LocalisableString name, LocalisableString count, LocalisableString time) + { + Name = name; + Count = count; + Time = time; + } } } From 4a590a041ccf6d755f81f8e052ac092d325ded05 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 20:57:36 +0300 Subject: [PATCH 743/961] Constrain difficulty icon tooltip to `internal` accessibility --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 5b05e39090..0329e935bc 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIconTooltip : VisibilityContainer, ITooltip + internal class DifficultyIconTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText difficultyName, starRating; private readonly Box background; @@ -107,7 +107,7 @@ namespace osu.Game.Beatmaps.Drawables protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); } - public class DifficultyIconTooltipContent + internal class DifficultyIconTooltipContent { public readonly BeatmapInfo Beatmap; public readonly IBindable Difficulty; From cd356b8eae1500a2f2127058b7686537d1fc4796 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 20:57:47 +0300 Subject: [PATCH 744/961] Revert "Constrain difficulty icon tooltip to `internal` accessibility" This reverts commit 4a590a041ccf6d755f81f8e052ac092d325ded05. --- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 0329e935bc..5b05e39090 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables { - internal class DifficultyIconTooltip : VisibilityContainer, ITooltip + public class DifficultyIconTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText difficultyName, starRating; private readonly Box background; @@ -107,7 +107,7 @@ namespace osu.Game.Beatmaps.Drawables protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); } - internal class DifficultyIconTooltipContent + public class DifficultyIconTooltipContent { public readonly BeatmapInfo Beatmap; public readonly IBindable Difficulty; From b0d7104650a125093d8ab6d354c45bfa630f74ee Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 21:13:20 +0300 Subject: [PATCH 745/961] Convert to `class` to allow not displaying tooltips With `struct` content, it is never possible to not show a tooltip. --- osu.Game/Overlays/Profile/UserGraph.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/UserGraph.cs b/osu.Game/Overlays/Profile/UserGraph.cs index f305e3afc3..182221eea7 100644 --- a/osu.Game/Overlays/Profile/UserGraph.cs +++ b/osu.Game/Overlays/Profile/UserGraph.cs @@ -125,7 +125,7 @@ namespace osu.Game.Overlays.Profile get { if (data == null || hoveredIndex == -1) - return default; + return null; var (key, value) = data[hoveredIndex]; return GetTooltipContent(key, value); @@ -295,7 +295,7 @@ namespace osu.Game.Overlays.Profile } } - public readonly struct UserGraphTooltipContent + public class UserGraphTooltipContent { // todo: could use init-only properties on C# 9 which read better than a constructor. public LocalisableString Name { get; } From 505824d8eaccfbd1f9e2550004ca65af7c49c8a4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 31 Aug 2021 21:16:02 +0300 Subject: [PATCH 746/961] Constrain difficulty icon tooltip to `internal` accessibility" This reverts the reverted commit cd356b8eae1500a2f2127058b7686537d1fc4796. Sorry for the revert-unrevert, rushly pushed without realizing it doesn't even build. --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ++-- osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index cda4377780..0751a777d8 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -126,9 +126,9 @@ namespace osu.Game.Beatmaps.Drawables difficultyBindable.BindValueChanged(difficulty => background.Colour = colours.ForStarDifficulty(difficulty.NewValue.Stars)); } - public ITooltip GetCustomTooltip() => new DifficultyIconTooltip(); + ITooltip IHasCustomTooltip.GetCustomTooltip() => new DifficultyIconTooltip(); - public DifficultyIconTooltipContent TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null; + DifficultyIconTooltipContent IHasCustomTooltip.TooltipContent => shouldShowTooltip ? new DifficultyIconTooltipContent(beatmap, difficultyBindable) : null; private class DifficultyRetriever : Component { diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs index 5b05e39090..0329e935bc 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIconTooltip.cs @@ -14,7 +14,7 @@ using osuTK; namespace osu.Game.Beatmaps.Drawables { - public class DifficultyIconTooltip : VisibilityContainer, ITooltip + internal class DifficultyIconTooltip : VisibilityContainer, ITooltip { private readonly OsuSpriteText difficultyName, starRating; private readonly Box background; @@ -107,7 +107,7 @@ namespace osu.Game.Beatmaps.Drawables protected override void PopOut() => this.FadeOut(200, Easing.OutQuint); } - public class DifficultyIconTooltipContent + internal class DifficultyIconTooltipContent { public readonly BeatmapInfo Beatmap; public readonly IBindable Difficulty; From da3fa9304aef4533246bb4b35f358cd536e3bf08 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 31 Aug 2021 12:39:18 -0700 Subject: [PATCH 747/961] Make toolbar inherit overlay container --- osu.Game/Overlays/Toolbar/Toolbar.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 2664301a0c..8184954753 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -18,7 +18,7 @@ using osu.Game.Input.Bindings; namespace osu.Game.Overlays.Toolbar { - public class Toolbar : VisibilityContainer, IKeyBindingHandler + public class Toolbar : OverlayContainer, IKeyBindingHandler { public const float HEIGHT = 40; public const float TOOLTIP_HEIGHT = 30; @@ -41,8 +41,6 @@ namespace osu.Game.Overlays.Toolbar // Toolbar and its components need keyboard input even when hidden. public override bool PropagateNonPositionalInputSubTree => true; - protected override bool Handle(UIEvent e) => e is MouseEvent; - public Toolbar() { RelativeSizeAxes = Axes.X; From 7e4ad7d7cfaf6e0dc435f157320807b26f12e184 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 31 Aug 2021 13:40:13 -0700 Subject: [PATCH 748/961] Fix toolbar blocking scroll input --- osu.Game/Overlays/Toolbar/Toolbar.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 8184954753..7481cfdbf5 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -41,6 +41,8 @@ namespace osu.Game.Overlays.Toolbar // Toolbar and its components need keyboard input even when hidden. public override bool PropagateNonPositionalInputSubTree => true; + protected override bool BlockScrollInput => false; + public Toolbar() { RelativeSizeAxes = Axes.X; From 04773b51bb6efa4964dc6df92158ea23aba679ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 31 Aug 2021 22:37:40 +0200 Subject: [PATCH 749/961] Remove countdown toggle transition for now Tricky to get right and the design isn't final as is anyway, so leaving *something* functioning as a best-effort for now. --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index d030c2a894..ede6a52276 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -16,8 +16,6 @@ namespace osu.Game.Screens.Edit.Setup { internal class DesignSection : SetupSection { - private const float fade_duration = 250; - protected LabelledSwitchButton EnableCountdown; protected LabelledEnumDropdown CountdownSpeed; protected LabelledNumberBox CountdownOffset; @@ -90,7 +88,6 @@ namespace osu.Game.Screens.Edit.Setup base.LoadComplete(); EnableCountdown.Current.BindValueChanged(_ => updateCountdownSettingsVisibility(), true); - countdownSettings.FinishTransforms(true); EnableCountdown.Current.BindValueChanged(_ => updateBeatmap()); CountdownSpeed.Current.BindValueChanged(_ => updateBeatmap()); @@ -101,16 +98,7 @@ namespace osu.Game.Screens.Edit.Setup letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); } - private void updateCountdownSettingsVisibility() - { - bool countdownEnabled = EnableCountdown.Current.Value; - - foreach (var child in countdownSettings) - { - child.ScaleTo(new Vector2(1, countdownEnabled ? 1 : 0), fade_duration, Easing.OutQuint) - .FadeTo(countdownEnabled ? 1 : 0, fade_duration, Easing.OutQuint); - } - } + private void updateCountdownSettingsVisibility() => countdownSettings.FadeTo(EnableCountdown.Current.Value ? 1 : 0); private void onOffsetCommitted() { From 5dc938cc9f09fc523fd838b7bea7ce7da7e3a908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 31 Aug 2021 22:40:58 +0200 Subject: [PATCH 750/961] Update tests to match expectations --- osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs | 9 ++++++--- osu.Game/Screens/Edit/Setup/DesignSection.cs | 8 ++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs index d84ffa1052..00f2979691 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDesignSection.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Linq; using NUnit.Framework; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -42,7 +43,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("turn countdown off", () => designSection.EnableCountdown.Current.Value = false); AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.None); - AddUntilStep("other controls hidden", () => !designSection.CountdownSpeed.IsPresent && !designSection.CountdownOffset.IsPresent); + AddUntilStep("other controls hidden", () => !designSection.CountdownSettings.IsPresent); } [Test] @@ -51,12 +52,12 @@ namespace osu.Game.Tests.Visual.Editing AddStep("turn countdown on", () => designSection.EnableCountdown.Current.Value = true); AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.Normal); - AddUntilStep("other controls shown", () => designSection.CountdownSpeed.IsPresent && designSection.CountdownOffset.IsPresent); + AddUntilStep("other controls shown", () => designSection.CountdownSettings.IsPresent); AddStep("change countdown speed", () => designSection.CountdownSpeed.Current.Value = CountdownType.DoubleSpeed); AddAssert("beatmap has correct type", () => editorBeatmap.BeatmapInfo.Countdown == CountdownType.DoubleSpeed); - AddUntilStep("other controls still shown", () => designSection.CountdownSpeed.IsPresent && designSection.CountdownOffset.IsPresent); + AddUntilStep("other controls still shown", () => designSection.CountdownSettings.IsPresent); } [Test] @@ -90,6 +91,8 @@ namespace osu.Game.Tests.Visual.Editing private class TestDesignSection : DesignSection { public new LabelledSwitchButton EnableCountdown => base.EnableCountdown; + + public new FillFlowContainer CountdownSettings => base.CountdownSettings; public new LabelledEnumDropdown CountdownSpeed => base.CountdownSpeed; public new LabelledNumberBox CountdownOffset => base.CountdownOffset; } diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index ede6a52276..90f95a668e 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -17,6 +17,8 @@ namespace osu.Game.Screens.Edit.Setup internal class DesignSection : SetupSection { protected LabelledSwitchButton EnableCountdown; + + protected FillFlowContainer CountdownSettings; protected LabelledEnumDropdown CountdownSpeed; protected LabelledNumberBox CountdownOffset; @@ -24,8 +26,6 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSwitchButton epilepsyWarning; private LabelledSwitchButton letterboxDuringBreaks; - private FillFlowContainer countdownSettings; - public override LocalisableString Title => "Design"; [BackgroundDependencyLoader] @@ -39,7 +39,7 @@ namespace osu.Game.Screens.Edit.Setup Current = { Value = Beatmap.BeatmapInfo.Countdown != CountdownType.None }, Description = "If enabled, an \"Are you ready? 3, 2, 1, GO!\" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." }, - countdownSettings = new FillFlowContainer + CountdownSettings = new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -98,7 +98,7 @@ namespace osu.Game.Screens.Edit.Setup letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); } - private void updateCountdownSettingsVisibility() => countdownSettings.FadeTo(EnableCountdown.Current.Value ? 1 : 0); + private void updateCountdownSettingsVisibility() => CountdownSettings.FadeTo(EnableCountdown.Current.Value ? 1 : 0); private void onOffsetCommitted() { From a773a22726c13aa0687c7630e91a312718c0fc1c Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 31 Aug 2021 14:29:16 -0700 Subject: [PATCH 751/961] Fix toolbar hiding when clicking home button --- osu.Game/OsuGame.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index a584644fc9..187669cbb4 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -160,7 +160,7 @@ namespace osu.Game private readonly string[] args; - private readonly List overlays = new List(); + private readonly List focusedOverlays = new List(); private readonly List visibleBlockingOverlays = new List(); @@ -195,7 +195,7 @@ namespace osu.Game /// Whether the toolbar should also be hidden. public void CloseAllOverlays(bool hideToolbar = true) { - foreach (var overlay in overlays) + foreach (var overlay in focusedOverlays) overlay.Hide(); if (hideToolbar) Toolbar.Hide(); @@ -910,8 +910,8 @@ namespace osu.Game if (cache) dependencies.CacheAs(component); - if (component is OverlayContainer overlay) - overlays.Add(overlay); + if (component is OsuFocusedOverlayContainer overlay) + focusedOverlays.Add(overlay); // schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached). // with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile, From bd0f385cdb5546f060dd73ee7f71e504475ac2a3 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 1 Sep 2021 14:53:11 +0900 Subject: [PATCH 752/961] Make classic scoring a constant multiple of standardised scoring --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 16f2607bad..2a7691269d 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -222,12 +222,12 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Standardised: double accuracyScore = accuracyPortion * accuracyRatio; double comboScore = comboPortion * comboRatio; - return (max_score * (accuracyScore + comboScore) + getBonusScore(statistics)) * scoreMultiplier; case ScoringMode.Classic: - // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) - return getBonusScore(statistics) + (accuracyRatio * Math.Max(1, maxCombo) * 300) * (1 + Math.Max(0, (comboRatio * maxCombo) - 1) * scoreMultiplier / 25); + // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. + // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. + return GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score * Math.Pow(maxCombo, 2) * 25; } } From 7a447f5128e87f965093f04c1840f6e531fdea9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 15:10:24 +0900 Subject: [PATCH 753/961] Mark `SankingSliderBody` as `abstract` --- osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs index ed4e04184b..7b7a89d5e2 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/SnakingSliderBody.cs @@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default /// /// A which changes its curve depending on the snaking progress. /// - public class SnakingSliderBody : SliderBody, ISliderProgress + public abstract class SnakingSliderBody : SliderBody, ISliderProgress { public readonly List CurrentCurve = new List(); From 4f9c3fde07a662ef43925aadb4cd562c2afed1ac Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 15:10:56 +0900 Subject: [PATCH 754/961] Move alpha adjustment back to `LegacySliderBody` to correctly handle default legacy skin --- .../Skinning/Default/PlaySliderBody.cs | 6 +++--- .../Skinning/Legacy/LegacySliderBody.cs | 7 +++++++ .../Legacy/OsuLegacySkinTransformer.cs | 21 ++----------------- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs index 4dd7b2d69c..8602ebc88b 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/PlaySliderBody.cs @@ -35,7 +35,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default pathVersion.BindValueChanged(_ => Refresh()); accentColour = drawableObject.AccentColour.GetBoundCopy(); - accentColour.BindValueChanged(accent => updateAccentColour(skin, accent.NewValue), true); + accentColour.BindValueChanged(accent => AccentColour = GetBodyAccentColour(skin, accent.NewValue), true); config?.BindWith(OsuRulesetSetting.SnakingInSliders, SnakingIn); config?.BindWith(OsuRulesetSetting.SnakingOutSliders, configSnakingOut); @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default } } - private void updateAccentColour(ISkinSource skin, Color4 defaultAccentColour) - => AccentColour = skin.GetConfig(OsuSkinColour.SliderTrackOverride)?.Value ?? defaultAccentColour; + protected virtual Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour) => + skin.GetConfig(OsuSkinColour.SliderTrackOverride)?.Value ?? hitObjectAccentColour; } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs index 7d69e5ecdc..29a0745193 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs @@ -5,6 +5,7 @@ using System; using osu.Framework.Extensions.Color4Extensions; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Default; +using osu.Game.Skinning; using osu.Game.Utils; using osuTK.Graphics; @@ -14,6 +15,12 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { protected override DrawableSliderPath CreateSliderPath() => new LegacyDrawableSliderPath(); + protected override Color4 GetBodyAccentColour(ISkinSource skin, Color4 hitObjectAccentColour) + { + // legacy skins use a constant value for slider track alpha, regardless of the source colour. + return base.GetBodyAccentColour(skin, hitObjectAccentColour).Opacity(0.7f); + } + private class LegacyDrawableSliderPath : DrawableSliderPath { private const float shadow_portion = 1 - (OsuLegacySkinTransformer.LEGACY_CIRCLE_RADIUS / OsuHitObject.OBJECT_RADIUS); diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs index 16c770706d..41b0a88f11 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/OsuLegacySkinTransformer.cs @@ -3,11 +3,9 @@ using System; using osu.Framework.Bindables; -using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Game.Skinning; using osuTK; -using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { @@ -120,23 +118,8 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { switch (lookup) { - case OsuSkinColour colourLookup: - var colour = base.GetConfig(new SkinCustomColourLookup(colourLookup)); - - if (colour == null) - return null; - - switch (colourLookup) - { - case OsuSkinColour.SliderTrackOverride: - var bindableColour = ((Bindable)colour); - - // legacy skins use a constant value for slider track alpha, regardless of the source colour. - bindableColour.Value = bindableColour.Value.Opacity(0.7f); - break; - } - - return colour; + case OsuSkinColour colour: + return base.GetConfig(new SkinCustomColourLookup(colour)); case OsuSkinConfiguration osuLookup: switch (osuLookup) From 88fc53200ed880b5836d1e6c1497e33dd8bb6316 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 1 Sep 2021 15:41:52 +0900 Subject: [PATCH 755/961] Refactor --- .../BeatmapSet/Scores/ScoresContainer.cs | 3 +- osu.Game/Scoring/ScoreManager.cs | 36 ++++++++---- osu.Game/Screens/Ranking/ScorePanelList.cs | 56 ++++++++++--------- .../Select/Leaderboards/BeatmapLeaderboard.cs | 4 +- 4 files changed, 59 insertions(+), 40 deletions(-) diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index a5a373467e..fb1769fbe1 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -14,7 +14,6 @@ using osu.Game.Beatmaps; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Framework.Bindables; -using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets; using osu.Game.Scoring; @@ -67,7 +66,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores if (value?.Scores.Any() != true) return; - scoreManager.GetOrderedScoresAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) + scoreManager.OrderByTotalScoreAsync(value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) .ContinueWith(ordered => Schedule(() => { if (loadCancellationSource.IsCancellationRequested) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 71edc65fcc..6fccf80b6c 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -34,7 +34,6 @@ namespace osu.Game.Scoring protected override string ImportFromStablePath => Path.Combine("Data", "r"); - private readonly Bindable scoringMode = new Bindable(); private readonly RulesetStore rulesets; private readonly Func beatmaps; @@ -52,8 +51,6 @@ namespace osu.Game.Scoring this.beatmaps = beatmaps; this.difficulties = difficulties; this.configManager = configManager; - - configManager?.BindWith(OsuSetting.ScoreDisplayMode, scoringMode); } protected override ScoreInfo CreateModel(ArchiveReader archive) @@ -106,14 +103,20 @@ namespace osu.Game.Scoring => base.CheckLocalAvailability(model, items) || (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID)); - public async Task GetOrderedScoresAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) + /// + /// Orders an array of s by total score. + /// + /// The array of s to reorder. + /// A to cancel the process. + /// The given ordered by decreasing total score. + public async Task OrderByTotalScoreAsync(ScoreInfo[] scores, CancellationToken cancellationToken = default) { var difficultyCache = difficulties?.Invoke(); if (difficultyCache == null) return orderByTotalScore(scores); - // Compute difficulties asynchronously first to prevent blocks on the main thread. + // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. foreach (var s in scores) { await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); @@ -122,7 +125,7 @@ namespace osu.Game.Scoring return orderByTotalScore(scores); - ScoreInfo[] orderByTotalScore(IEnumerable incoming) => incoming.OrderByDescending(GetTotalScore).ThenBy(s => s.OnlineScoreID).ToArray(); + ScoreInfo[] orderByTotalScore(IEnumerable incoming) => incoming.OrderByDescending(s => GetTotalScore(s)).ThenBy(s => s.OnlineScoreID).ToArray(); } /// @@ -150,9 +153,22 @@ namespace osu.Game.Scoring /// The bindable containing the formatted total score string. public Bindable GetBindableTotalScoreString(ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score)); - public long GetTotalScore(ScoreInfo score) => GetTotalScoreAsync(score).Result; + /// + /// Retrieves the total score of a in the given . + /// + /// The to calculate the total score of. + /// The to return the total score as. + /// The total score. + public long GetTotalScore(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => GetTotalScoreAsync(score).Result; - public async Task GetTotalScoreAsync(ScoreInfo score, CancellationToken cancellationToken = default) + /// + /// Retrieves the total score of a in the given . + /// + /// The to calculate the total score of. + /// The to return the total score as. + /// A to cancel the process. + /// The total score. + public async Task GetTotalScoreAsync(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) { if (score.Beatmap == null) return score.TotalScore; @@ -204,7 +220,7 @@ namespace osu.Game.Scoring var scoreProcessor = ruleset.CreateScoreProcessor(); scoreProcessor.Mods.Value = score.Mods; - return (long)Math.Round(scoreProcessor.GetScore(scoringMode.Value, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics)); + return (long)Math.Round(scoreProcessor.GetScore(mode, beatmapMaxCombo, accuracy, (double)score.MaxCombo / beatmapMaxCombo, score.Statistics)); } /// @@ -221,7 +237,7 @@ namespace osu.Game.Scoring /// The . public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager) { - ScoringMode.BindValueChanged(_ => Value = scoreManager.GetTotalScore(score), true); + ScoringMode.BindValueChanged(mode => Value = scoreManager.GetTotalScore(score, mode.NewValue), true); } } diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index e319e824a1..b0c06ebe6a 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -11,6 +11,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Game.Beatmaps; using osu.Game.Graphics.Containers; using osu.Game.Scoring; using osuTK; @@ -65,6 +66,9 @@ namespace osu.Game.Screens.Ranking [Resolved] private ScoreManager scoreManager { get; set; } + [Resolved] + private BeatmapDifficultyCache difficultyCache { get; set; } + private readonly CancellationTokenSource loadCancellationSource = new CancellationTokenSource(); private readonly Flow flow; private readonly Scroll scroll; @@ -120,33 +124,33 @@ namespace osu.Game.Screens.Ranking }; }); - scoreManager.GetOrderedScoresAsync(new[] { score }) - .ContinueWith(_ => Schedule(() => - { - flow.Add(panel.CreateTrackingContainer().With(d => - { - d.Anchor = Anchor.Centre; - d.Origin = Anchor.Centre; - })); + difficultyCache.GetDifficultyAsync(score.Beatmap, score.Ruleset, score.Mods) + .ContinueWith(_ => Schedule(() => + { + flow.Add(panel.CreateTrackingContainer().With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + })); - if (SelectedScore.Value == score) - { - SelectedScore.TriggerChange(); - } - else - { - // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. - // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. - if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) - { - // A somewhat hacky property is used here because we need to: - // 1) Scroll after the scroll container's visible range is updated. - // 2) Scroll before the scroll container's scroll position is updated. - // Without this, we would have a 1-frame positioning error which looks very jarring. - scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; - } - } - })); + if (SelectedScore.Value == score) + { + SelectedScore.TriggerChange(); + } + else + { + // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. + // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. + if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + { + // A somewhat hacky property is used here because we need to: + // 1) Scroll after the scroll container's visible range is updated. + // 2) Scroll before the scroll container's scroll position is updated. + // Without this, we would have a 1-frame positioning error which looks very jarring. + scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + } + } + })); return panel; } diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 54ec42127d..7820264505 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -156,7 +156,7 @@ namespace osu.Game.Screens.Select.Leaderboards scores = scores.Where(s => s.Mods.Any(m => selectedMods.Contains(m.Acronym))); } - scoreManager.GetOrderedScoresAsync(scores.ToArray(), loadCancellationSource.Token) + scoreManager.OrderByTotalScoreAsync(scores.ToArray(), loadCancellationSource.Token) .ContinueWith(ordered => scoresCallback?.Invoke(ordered.Result), TaskContinuationOptions.OnlyOnRanToCompletion); return null; @@ -192,7 +192,7 @@ namespace osu.Game.Screens.Select.Leaderboards req.Success += r => { - scoreManager.GetOrderedScoresAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) + scoreManager.OrderByTotalScoreAsync(r.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToArray(), loadCancellationSource.Token) .ContinueWith(ordered => Schedule(() => { if (loadCancellationSource.IsCancellationRequested) From 0319177c5c10b8eff6f71f202005a676731b3c3b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 16:46:19 +0900 Subject: [PATCH 756/961] Fix pixels poking out of the top edge of editor setup screen --- osu.Game/Screens/Edit/Setup/SetupScreen.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 72bf3ad67e..746cf38867 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -25,7 +25,7 @@ namespace osu.Game.Screens.Edit.Setup { AddRange(new Drawable[] { - sections = new SectionsContainer + sections = new SetupScreenSectionsContainer { FixedHeader = header, RelativeSizeAxes = Axes.Both, @@ -40,5 +40,19 @@ namespace osu.Game.Screens.Edit.Setup }, }); } + + private class SetupScreenSectionsContainer : SectionsContainer + { + protected override UserTrackingScrollContainer CreateScrollContainer() + { + var scrollContainer = base.CreateScrollContainer(); + + // Workaround for masking issues (see https://github.com/ppy/osu-framework/issues/1675#issuecomment-910023157) + // Note that this actually causes the full scroll range to be reduced by 2px at the bottom, but it's not really noticeable. + scrollContainer.Margin = new MarginPadding { Top = 2 }; + + return scrollContainer; + } + } } } From 2251bf3bcbdb82f706ba81624faf6a943b60324a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 17:08:20 +0900 Subject: [PATCH 757/961] Use lambda spec for method --- .../Profile/Sections/Historical/UserHistoryGraph.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs index 738edb9310..61f77cd6ff 100644 --- a/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs +++ b/osu.Game/Overlays/Profile/Sections/Historical/UserHistoryGraph.cs @@ -28,12 +28,10 @@ namespace osu.Game.Overlays.Profile.Sections.Historical protected override float GetDataPointHeight(long playCount) => playCount; - protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) - { - return new UserGraphTooltipContent( + protected override UserGraphTooltipContent GetTooltipContent(DateTime date, long playCount) => + new UserGraphTooltipContent( tooltipCounterName, playCount.ToLocalisableString("N0"), date.ToLocalisableString("MMMM yyyy")); - } } } From fb5f3fb9af60aa071992513eb6228a81a6a1bf1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 17:19:38 +0900 Subject: [PATCH 758/961] Rename button to be more descriptive of its purpose --- ...ayerModButton.cs => IncompatibilityDisplayingModButton.cs} | 4 ++-- osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename osu.Game/Overlays/Mods/{LocalPlayerModButton.cs => IncompatibilityDisplayingModButton.cs} (96%) diff --git a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs similarity index 96% rename from osu.Game/Overlays/Mods/LocalPlayerModButton.cs rename to osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs index d26bbf344d..e232081dde 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModButton.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs @@ -18,14 +18,14 @@ using osuTK; namespace osu.Game.Overlays.Mods { - public class LocalPlayerModButton : ModButton + public class IncompatibilityDisplayingModButton : ModButton { private readonly CompositeDrawable incompatibleIcon; [Resolved] private Bindable> selectedMods { get; set; } - public LocalPlayerModButton(Mod mod) + public IncompatibilityDisplayingModButton(Mod mod) : base(mod) { ButtonContent.Add(incompatibleIcon = new IncompatibleIcon diff --git a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs b/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs index b8e0c27007..c872f2c79d 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs @@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Mods { } - protected override ModButton CreateModButton(Mod mod) => new LocalPlayerModButton(mod); + protected override ModButton CreateModButton(Mod mod) => new IncompatibilityDisplayingModButton(mod); } } } From 9e21f5a59c8d476af6f1d66334c9395ecd18dbe4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 1 Sep 2021 17:22:52 +0900 Subject: [PATCH 759/961] Rename `LocalPlayer` to `User` in mod select prefixes --- osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs | 2 +- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 2 +- .../Visual/UserInterface/TestSceneModSettings.cs | 2 +- .../Overlays/Mods/IncompatibilityDisplayingModButton.cs | 6 +++--- ...lPlayerModSelectOverlay.cs => UserModSelectOverlay.cs} | 8 ++++---- osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs | 4 ---- osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 8 files changed, 12 insertions(+), 16 deletions(-) rename osu.Game/Overlays/Mods/{LocalPlayerModSelectOverlay.cs => UserModSelectOverlay.cs} (77%) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 22338bad84..0b70703870 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -529,7 +529,7 @@ namespace osu.Game.Tests.Visual.Multiplayer AddStep("invoke on back button", () => multiplayerScreen.OnBackButton()); - AddAssert("mod overlay is hidden", () => this.ChildrenOfType().Single().State.Value == Visibility.Hidden); + AddAssert("mod overlay is hidden", () => this.ChildrenOfType().Single().State.Value == Visibility.Hidden); AddAssert("dialog overlay is hidden", () => DialogOverlay.State.Value == Visibility.Hidden); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 32c1d262d5..9e253e089d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -422,7 +422,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; } - private class TestModSelectOverlay : LocalPlayerModSelectOverlay + private class TestModSelectOverlay : UserModSelectOverlay { public new Bindable> SelectedMods => base.SelectedMods; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs index 84e2ebb6d8..da0fa5d76d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSettings.cs @@ -151,7 +151,7 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait for ready", () => modSelect.State.Value == Visibility.Visible && modSelect.ButtonsLoaded); } - private class TestModSelectOverlay : LocalPlayerModSelectOverlay + private class TestModSelectOverlay : UserModSelectOverlay { public new VisibilityContainer ModSettingsContainer => base.ModSettingsContainer; public new TriangleButton CustomiseButton => base.CustomiseButton; diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs index e232081dde..c8e44ee159 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs @@ -65,9 +65,9 @@ namespace osu.Game.Overlays.Mods incompatibleIcon.Hide(); } - public override ITooltip GetCustomTooltip() => new LocalPlayerModButtonTooltip(); + public override ITooltip GetCustomTooltip() => new IncompatibilityDisplayingTooltip(); - private class LocalPlayerModButtonTooltip : ModButtonTooltip + private class IncompatibilityDisplayingTooltip : ModButtonTooltip { private readonly OsuSpriteText incompatibleText; @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.Mods [Resolved] private Bindable ruleset { get; set; } - public LocalPlayerModButtonTooltip() + public IncompatibilityDisplayingTooltip() { AddRange(new Drawable[] { diff --git a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs similarity index 77% rename from osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs rename to osu.Game/Overlays/Mods/UserModSelectOverlay.cs index c872f2c79d..161f89c2eb 100644 --- a/osu.Game/Overlays/Mods/LocalPlayerModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/UserModSelectOverlay.cs @@ -5,7 +5,7 @@ using osu.Game.Rulesets.Mods; namespace osu.Game.Overlays.Mods { - public class LocalPlayerModSelectOverlay : ModSelectOverlay + public class UserModSelectOverlay : ModSelectOverlay { protected override void OnModSelected(Mod mod) { @@ -15,11 +15,11 @@ namespace osu.Game.Overlays.Mods section.DeselectTypes(mod.IncompatibleMods, true, mod); } - protected override ModSection CreateModSection(ModType type) => new LocalPlayerModSection(type); + protected override ModSection CreateModSection(ModType type) => new UserModSection(type); - private class LocalPlayerModSection : ModSection + private class UserModSection : ModSection { - public LocalPlayerModSection(ModType type) + public UserModSection(ModType type) : base(type) { } diff --git a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs index c05022a903..9095b78eb4 100644 --- a/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Match/RoomSubScreen.cs @@ -429,10 +429,6 @@ namespace osu.Game.Screens.OnlinePlay.Match /// The room to change the settings of. protected abstract RoomSettingsOverlay CreateRoomSettingsOverlay(Room room); - private class UserModSelectOverlay : LocalPlayerModSelectOverlay - { - } - public class UserModSelectButton : PurpleTriangleButton { } diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index 1a063fd6c6..4bc0b55433 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -152,7 +152,7 @@ namespace osu.Game.Screens.OnlinePlay return base.OnExiting(next); } - protected override ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay + protected override ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay { IsValidMod = IsValidMod }; diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index bb3df0d4e0..b3d715e580 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -315,7 +315,7 @@ namespace osu.Game.Screens.Select (new FooterButtonOptions(), BeatmapOptions) }; - protected virtual ModSelectOverlay CreateModSelectOverlay() => new LocalPlayerModSelectOverlay(); + protected virtual ModSelectOverlay CreateModSelectOverlay() => new UserModSelectOverlay(); protected virtual void ApplyFilterToCarousel(FilterCriteria criteria) { From ab538dc3dd4474961c2235c46d4223892e29cf60 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 1 Sep 2021 20:30:26 +0900 Subject: [PATCH 760/961] Fix param not passed through --- osu.Game/Scoring/ScoreManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 6fccf80b6c..9b94e34f75 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -159,7 +159,7 @@ namespace osu.Game.Scoring /// The to calculate the total score of. /// The to return the total score as. /// The total score. - public long GetTotalScore(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => GetTotalScoreAsync(score).Result; + public long GetTotalScore(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => GetTotalScoreAsync(score, mode).Result; /// /// Retrieves the total score of a in the given . From f7c1177cc9ec585583a549e81e834aa581819e64 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 1 Sep 2021 20:35:06 +0900 Subject: [PATCH 761/961] Fix ScorePanelList nullref when scores are added too soon --- .../Visual/Ranking/TestSceneScorePanelList.cs | 16 ++++ osu.Game/Screens/Ranking/ScorePanelList.cs | 95 ++++++++++--------- 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs index e65dcb19b1..f330e99d55 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs @@ -182,6 +182,22 @@ namespace osu.Game.Tests.Visual.Ranking assertExpandedPanelCentred(); } + [Test] + public void TestAddScoreImmediately() + { + var score = new TestScoreInfo(new OsuRuleset().RulesetInfo); + + createListStep(() => + { + var newList = new ScorePanelList { SelectedScore = { Value = score } }; + newList.AddScore(score); + return newList; + }); + + assertScoreState(score, true); + assertExpandedPanelCentred(); + } + private void createListStep(Func creationFunc) { AddStep("create list", () => Child = list = creationFunc().With(d => diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index b0c06ebe6a..711e0d60ec 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -100,6 +101,9 @@ namespace osu.Game.Screens.Ranking { base.LoadComplete(); + foreach (var d in flow) + displayScore(d); + SelectedScore.BindValueChanged(selectedScoreChanged, true); } @@ -124,37 +128,56 @@ namespace osu.Game.Screens.Ranking }; }); - difficultyCache.GetDifficultyAsync(score.Beatmap, score.Ruleset, score.Mods) - .ContinueWith(_ => Schedule(() => - { - flow.Add(panel.CreateTrackingContainer().With(d => - { - d.Anchor = Anchor.Centre; - d.Origin = Anchor.Centre; - })); + var trackingContainer = panel.CreateTrackingContainer().With(d => + { + d.Anchor = Anchor.Centre; + d.Origin = Anchor.Centre; + d.Hide(); + }); - if (SelectedScore.Value == score) - { - SelectedScore.TriggerChange(); - } - else - { - // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. - // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. - if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) - { - // A somewhat hacky property is used here because we need to: - // 1) Scroll after the scroll container's visible range is updated. - // 2) Scroll before the scroll container's scroll position is updated. - // Without this, we would have a 1-frame positioning error which looks very jarring. - scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; - } - } - })); + flow.Add(trackingContainer); + + if (IsLoaded) + displayScore(trackingContainer); return panel; } + private void displayScore(ScorePanelTrackingContainer trackingContainer) + { + if (!IsLoaded) + return; + + var score = trackingContainer.Panel.Score; + + // Calculating score can take a while in extreme scenarios, so only display scores after the process completes. + scoreManager.GetTotalScoreAsync(score) + .ContinueWith(totalScore => Schedule(() => + { + flow.SetLayoutPosition(trackingContainer, totalScore.Result); + + trackingContainer.Show(); + + if (SelectedScore.Value == score) + { + SelectedScore.TriggerChange(); + } + else + { + // We want the scroll position to remain relative to the expanded panel. When a new panel is added after the expanded panel, nothing needs to be done. + // But when a panel is added before the expanded panel, we need to offset the scroll position by the width of the new panel. + if (expandedPanel != null && flow.GetPanelIndex(score) < flow.GetPanelIndex(expandedPanel.Score)) + { + // A somewhat hacky property is used here because we need to: + // 1) Scroll after the scroll container's visible range is updated. + // 2) Scroll before the scroll container's scroll position is updated. + // Without this, we would have a 1-frame positioning error which looks very jarring. + scroll.InstantScrollTarget = (scroll.InstantScrollTarget ?? scroll.Target) + ScorePanel.CONTRACTED_WIDTH + panel_spacing; + } + } + }), TaskContinuationOptions.OnlyOnRanToCompletion); + } + /// /// Brings a to the centre of the screen and expands it. /// @@ -306,28 +329,8 @@ namespace osu.Game.Screens.Ranking { public override IEnumerable FlowingChildren => applySorting(AliveInternalChildren); - [Resolved] - private ScoreManager scoreManager { get; set; } - - protected override void LoadComplete() - { - base.LoadComplete(); - - foreach (var c in Children) - SetLayoutPosition(c, scoreManager.GetTotalScore(c.Panel.Score)); - } - public int GetPanelIndex(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Panel.Score != score).Count(); - public override void Add(ScorePanelTrackingContainer drawable) - { - Debug.Assert(drawable != null); - - base.Add(drawable); - - SetLayoutPosition(drawable, scoreManager?.GetTotalScore(drawable.Panel.Score) ?? 0); - } - private IEnumerable applySorting(IEnumerable drawables) => drawables.OfType() .OrderByDescending(GetLayoutPosition) .ThenBy(s => s.Panel.Score.OnlineScoreID); From df7480e68cc4d8d3f3fcec7a70e2b4c4db0b4854 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 1 Sep 2021 20:56:23 +0900 Subject: [PATCH 762/961] Fix bindable implementation being synchronous --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 2 +- .../TestSceneDeleteLocalScore.cs | 2 +- osu.Game/Scoring/ScoreManager.cs | 49 +++++++++++++++---- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 184a2e59da..29815ce9ff 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.SongSelect dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler)); return dependencies; } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 3f9e0048dd..98482601ee 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -82,7 +82,7 @@ namespace osu.Game.Tests.Visual.UserInterface dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); - dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory, Scheduler)); beatmap = beatmapManager.Import(new ImportTask(TestResources.GetQuickTestBeatmapForImport())).Result.Beatmaps[0]; diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 9b94e34f75..2cda8959f4 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -13,6 +13,7 @@ using Microsoft.EntityFrameworkCore; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Platform; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Database; @@ -36,6 +37,7 @@ namespace osu.Game.Scoring private readonly RulesetStore rulesets; private readonly Func beatmaps; + private readonly Scheduler scheduler; [CanBeNull] private readonly Func difficulties; @@ -43,12 +45,13 @@ namespace osu.Game.Scoring [CanBeNull] private readonly OsuConfigManager configManager; - public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null, - Func difficulties = null, OsuConfigManager configManager = null) + public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, Scheduler scheduler, + IIpcHost importHost = null, Func difficulties = null, OsuConfigManager configManager = null) : base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost) { this.rulesets = rulesets; this.beatmaps = beatmaps; + this.scheduler = scheduler; this.difficulties = difficulties; this.configManager = configManager; } @@ -125,7 +128,13 @@ namespace osu.Game.Scoring return orderByTotalScore(scores); - ScoreInfo[] orderByTotalScore(IEnumerable incoming) => incoming.OrderByDescending(s => GetTotalScore(s)).ThenBy(s => s.OnlineScoreID).ToArray(); + ScoreInfo[] orderByTotalScore(IEnumerable incoming) + { + // We're calling .Result, but this should not be a blocking call due to the above GetDifficultyAsync() calls. + return incoming.OrderByDescending(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken).Result) + .ThenBy(s => s.OnlineScoreID) + .ToArray(); + } } /// @@ -136,7 +145,7 @@ namespace osu.Game.Scoring /// /// The to retrieve the bindable for. /// The bindable containing the total score. - public Bindable GetBindableTotalScore(ScoreInfo score) + public Bindable GetBindableTotalScore([NotNull] ScoreInfo score) { var bindable = new TotalScoreBindable(score, this); configManager?.BindWith(OsuSetting.ScoreDisplayMode, bindable.ScoringMode); @@ -151,15 +160,21 @@ namespace osu.Game.Scoring /// /// The to retrieve the bindable for. /// The bindable containing the formatted total score string. - public Bindable GetBindableTotalScoreString(ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score)); + public Bindable GetBindableTotalScoreString([NotNull] ScoreInfo score) => new TotalScoreStringBindable(GetBindableTotalScore(score)); /// /// Retrieves the total score of a in the given . + /// The score is returned in a callback that is run on the update thread. /// /// The to calculate the total score of. + /// The callback to be invoked with the total score. /// The to return the total score as. - /// The total score. - public long GetTotalScore(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => GetTotalScoreAsync(score, mode).Result; + /// A to cancel the process. + public void GetTotalScore([NotNull] ScoreInfo score, [NotNull] Action callback, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) + { + GetTotalScoreAsync(score, mode, cancellationToken) + .ContinueWith(s => scheduler.Add(() => callback(s.Result)), TaskContinuationOptions.OnlyOnRanToCompletion); + } /// /// Retrieves the total score of a in the given . @@ -168,7 +183,7 @@ namespace osu.Game.Scoring /// The to return the total score as. /// A to cancel the process. /// The total score. - public async Task GetTotalScoreAsync(ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) + public async Task GetTotalScoreAsync([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default) { if (score.Beatmap == null) return score.TotalScore; @@ -230,6 +245,11 @@ namespace osu.Game.Scoring { public readonly Bindable ScoringMode = new Bindable(); + private readonly ScoreInfo score; + private readonly ScoreManager scoreManager; + + private CancellationTokenSource difficultyCalculationCancellationSource; + /// /// Creates a new . /// @@ -237,7 +257,18 @@ namespace osu.Game.Scoring /// The . public TotalScoreBindable(ScoreInfo score, ScoreManager scoreManager) { - ScoringMode.BindValueChanged(mode => Value = scoreManager.GetTotalScore(score, mode.NewValue), true); + this.score = score; + this.scoreManager = scoreManager; + + ScoringMode.BindValueChanged(onScoringModeChanged, true); + } + + private void onScoringModeChanged(ValueChangedEvent mode) + { + difficultyCalculationCancellationSource?.Cancel(); + difficultyCalculationCancellationSource = new CancellationTokenSource(); + + scoreManager.GetTotalScore(score, s => Value = s, mode.NewValue, difficultyCalculationCancellationSource.Token); } } From 492209fe13b80b94e7aa6602489ac0c00fa067a5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 17:01:49 +0000 Subject: [PATCH 763/961] Bump Sentry from 3.8.3 to 3.9.0 Bumps [Sentry](https://github.com/getsentry/sentry-dotnet) from 3.8.3 to 3.9.0. - [Release notes](https://github.com/getsentry/sentry-dotnet/releases) - [Changelog](https://github.com/getsentry/sentry-dotnet/blob/main/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-dotnet/compare/3.8.3...3.9.0) --- updated-dependencies: - dependency-name: Sentry dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4d4aa3070..75ba85e3ef 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -38,7 +38,7 @@ - + From 6f0d1b394d6d4699404c27b152e711b923d342fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 17:01:53 +0000 Subject: [PATCH 764/961] Bump Microsoft.AspNetCore.SignalR.Protocols.MessagePack Bumps [Microsoft.AspNetCore.SignalR.Protocols.MessagePack](https://github.com/dotnet/aspnetcore) from 5.0.8 to 5.0.9. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.8...v5.0.9) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Protocols.MessagePack dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index b4d4aa3070..bd42923413 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -24,7 +24,7 @@ - + From c5597b7d9ced6af9d81f5b2ad9b08809a6514b17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 17:02:03 +0000 Subject: [PATCH 765/961] Bump BenchmarkDotNet from 0.13.0 to 0.13.1 Bumps [BenchmarkDotNet](https://github.com/dotnet/BenchmarkDotNet) from 0.13.0 to 0.13.1. - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.0...v0.13.1) --- updated-dependencies: - dependency-name: BenchmarkDotNet dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game.Benchmarks/osu.Game.Benchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj index da8a0540f4..03f39f226c 100644 --- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj +++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj @@ -7,7 +7,7 @@ - + From 860f04af0031d6fcd455489dfcd864fbdc3a62a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 17:02:11 +0000 Subject: [PATCH 766/961] Bump ppy.osu.Framework.NativeLibs from 2021.115.0 to 2021.805.0 Bumps [ppy.osu.Framework.NativeLibs](https://github.com/ppy/osu-framework) from 2021.115.0 to 2021.805.0. - [Release notes](https://github.com/ppy/osu-framework/releases) - [Commits](https://github.com/ppy/osu-framework/compare/2021.115.0...2021.805.0) --- updated-dependencies: - dependency-name: ppy.osu.Framework.NativeLibs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- osu.iOS.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.iOS.props b/osu.iOS.props index 29e9b9fe20..1714bae53c 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -98,7 +98,7 @@ - + From 5a1eccd8e3a5fb8f5241abda8753e1a432d58649 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 18:17:37 +0000 Subject: [PATCH 767/961] Bump Microsoft.NET.Test.Sdk from 16.10.0 to 16.11.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.10.0 to 16.11.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.10.0...v16.11.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .../osu.Game.Rulesets.EmptyFreeform.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.EmptyScrolling.Tests.csproj | 2 +- .../osu.Game.Rulesets.Pippidon.Tests.csproj | 2 +- .../osu.Game.Rulesets.Catch.Tests.csproj | 2 +- .../osu.Game.Rulesets.Mania.Tests.csproj | 2 +- osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj | 2 +- .../osu.Game.Rulesets.Taiko.Tests.csproj | 2 +- osu.Game.Tests/osu.Game.Tests.csproj | 2 +- osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj index 3dd6be7307..e28053d0ca 100644 --- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj +++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 0c4bfe0ed7..027bd0b7e2 100644 --- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj index bb0a487274..e2c715d385 100644 --- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj index 0c4bfe0ed7..027bd0b7e2 100644 --- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj +++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj @@ -10,7 +10,7 @@ - + diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj index 484da8e22e..6457ec92da 100644 --- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj +++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj index 6df555617b..674a22df98 100644 --- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj +++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj index 68be34d153..f5f1159542 100644 --- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj +++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj index 532fdc5cb0..b9b295767e 100644 --- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj +++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj @@ -2,7 +2,7 @@ - + diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj index 161e248d96..696f930467 100644 --- a/osu.Game.Tests/osu.Game.Tests.csproj +++ b/osu.Game.Tests/osu.Game.Tests.csproj @@ -3,7 +3,7 @@ - + diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj index ba096abd36..2673c9ec9f 100644 --- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj +++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj @@ -5,7 +5,7 @@ - + From f14d66aafce778d86e2cc203afd0828d4c60293c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Sep 2021 10:35:00 +0900 Subject: [PATCH 768/961] Commit missed line --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 69f6bc1b7b..16e3cdbfda 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -262,7 +262,7 @@ namespace osu.Game dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Scheduler, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appears where it is necessary From 8ba00f673764d916882665fd9461a9b43bde4a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Sep 2021 02:33:56 +0000 Subject: [PATCH 769/961] Bump HtmlAgilityPack from 1.11.34 to 1.11.36 Bumps [HtmlAgilityPack](https://github.com/zzzprojects/html-agility-pack) from 1.11.34 to 1.11.36. - [Release notes](https://github.com/zzzprojects/html-agility-pack/releases) - [Commits](https://github.com/zzzprojects/html-agility-pack/compare/v1.11.34...v1.11.36) --- updated-dependencies: - dependency-name: HtmlAgilityPack dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3ed8e31c85..36fa178189 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -20,7 +20,7 @@ - + From be379051f2684d033fd0e30416ecb1cdad225dc0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Sep 2021 02:34:19 +0000 Subject: [PATCH 770/961] Bump Microsoft.AspNetCore.SignalR.Client from 5.0.8 to 5.0.9 Bumps [Microsoft.AspNetCore.SignalR.Client](https://github.com/dotnet/aspnetcore) from 5.0.8 to 5.0.9. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.8...v5.0.9) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Client dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3ed8e31c85..710aad7336 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -23,7 +23,7 @@ - + From e176babb258578c76e0cd3573fe3c337de9c779a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Sep 2021 02:34:24 +0000 Subject: [PATCH 771/961] Bump Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson Bumps [Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson](https://github.com/dotnet/aspnetcore) from 5.0.8 to 5.0.9. - [Release notes](https://github.com/dotnet/aspnetcore/releases) - [Commits](https://github.com/dotnet/aspnetcore/compare/v5.0.8...v5.0.9) --- updated-dependencies: - dependency-name: Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- osu.Game/osu.Game.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 3ed8e31c85..1f2b78f5ba 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -25,7 +25,7 @@ - + From 31433c4b894c80063d78865e9e81658653d6b013 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Sep 2021 16:26:17 +0900 Subject: [PATCH 772/961] Apply @spaceman_atlas' quadratic factor --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index 2a7691269d..e09225f967 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -227,7 +227,8 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. - return GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score * Math.Pow(maxCombo, 2) * 25; + var scaledStandardised = GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score; + return Math.Pow(scaledStandardised * maxCombo, 2) * 18; } } From b907c2f4f6bb37c22428520c238b7d6861ec5fde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 2 Sep 2021 16:31:43 +0900 Subject: [PATCH 773/961] Fix osu! judgements getting scaled twice over different durations --- .../UI/DrawableManiaJudgement.cs | 5 +++-- .../Objects/Drawables/DrawableOsuJudgement.cs | 10 ++++++--- .../UI/DrawableTaikoJudgement.cs | 22 +++++++++++++++++++ .../Judgements/DefaultJudgementPiece.cs | 13 ++++++----- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs index 34d972e60f..8581f016b1 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaJudgement.cs @@ -37,12 +37,11 @@ namespace osu.Game.Rulesets.Mania.UI public override void PlayAnimation() { - base.PlayAnimation(); - switch (Result) { case HitResult.None: case HitResult.Miss: + base.PlayAnimation(); break; default: @@ -52,6 +51,8 @@ namespace osu.Game.Rulesets.Mania.UI this.Delay(50) .ScaleTo(0.75f, 250) .FadeOut(200); + + // osu!mania uses a custom fade length, so the base call is intentionally omitted. break; } } diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs index b23087a1f3..e4df41a4fe 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableOsuJudgement.cs @@ -74,10 +74,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables public override void PlayAnimation() { - base.PlayAnimation(); - if (Result != HitResult.Miss) - JudgementText.ScaleTo(new Vector2(0.8f, 1)).Then().ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint); + { + JudgementText + .ScaleTo(new Vector2(0.8f, 1)) + .ScaleTo(new Vector2(1.2f, 1), 1800, Easing.OutQuint); + } + + base.PlayAnimation(); } } } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs index 1ad1e4495c..876fa207bf 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoJudgement.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Taiko.UI { @@ -16,5 +17,26 @@ namespace osu.Game.Rulesets.Taiko.UI this.MoveToY(-100, 500); base.ApplyHitAnimations(); } + + protected override Drawable CreateDefaultJudgement(HitResult result) => new TaikoJudgementPiece(result); + + private class TaikoJudgementPiece : DefaultJudgementPiece + { + public TaikoJudgementPiece(HitResult result) + : base(result) + { + } + + public override void PlayAnimation() + { + if (Result != HitResult.Miss) + { + JudgementText.ScaleTo(0.9f); + JudgementText.ScaleTo(1, 500, Easing.OutElastic); + } + + base.PlayAnimation(); + } + } } } diff --git a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs index 21ac017685..29b771a81d 100644 --- a/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs +++ b/osu.Game/Rulesets/Judgements/DefaultJudgementPiece.cs @@ -47,6 +47,13 @@ namespace osu.Game.Rulesets.Judgements }; } + /// + /// Plays the default animation for this judgement piece. + /// + /// + /// The base implementation only handles fade (for all result types) and misses. + /// Individual rulesets are recommended to implement their appropriate hit animations. + /// public virtual void PlayAnimation() { switch (Result) @@ -60,12 +67,6 @@ namespace osu.Game.Rulesets.Judgements this.RotateTo(0); this.RotateTo(40, 800, Easing.InQuint); - - break; - - default: - this.ScaleTo(0.9f); - this.ScaleTo(1, 500, Easing.OutElastic); break; } From e2f7aaeb71bbe841e91e61f0433ed40d3886c265 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Sep 2021 17:00:13 +0900 Subject: [PATCH 774/961] Fix 0 score with bonus-only maps --- osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs index e09225f967..c1234f8fb3 100644 --- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs +++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs @@ -227,8 +227,8 @@ namespace osu.Game.Rulesets.Scoring case ScoringMode.Classic: // This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring. // The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes. - var scaledStandardised = GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score; - return Math.Pow(scaledStandardised * maxCombo, 2) * 18; + double scaledStandardised = GetScore(ScoringMode.Standardised, maxCombo, accuracyRatio, comboRatio, statistics) / max_score; + return Math.Pow(scaledStandardised * (maxCombo + 1), 2) * 18; } } From e3ec7e3ddc7972b0bad19d1750ea0faffd4edc99 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 2 Sep 2021 17:01:09 +0900 Subject: [PATCH 775/961] Adjust test values --- .../Rulesets/Scoring/ScoreProcessorTest.cs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs index 184a94912a..f0d9ece06f 100644 --- a/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs +++ b/osu.Game.Tests/Rulesets/Scoring/ScoreProcessorTest.cs @@ -36,9 +36,9 @@ namespace osu.Game.Tests.Rulesets.Scoring [TestCase(ScoringMode.Standardised, HitResult.Meh, 750_000)] [TestCase(ScoringMode.Standardised, HitResult.Ok, 800_000)] [TestCase(ScoringMode.Standardised, HitResult.Great, 1_000_000)] - [TestCase(ScoringMode.Classic, HitResult.Meh, 50)] - [TestCase(ScoringMode.Classic, HitResult.Ok, 100)] - [TestCase(ScoringMode.Classic, HitResult.Great, 300)] + [TestCase(ScoringMode.Classic, HitResult.Meh, 41)] + [TestCase(ScoringMode.Classic, HitResult.Ok, 46)] + [TestCase(ScoringMode.Classic, HitResult.Great, 72)] public void TestSingleOsuHit(ScoringMode scoringMode, HitResult hitResult, int expectedScore) { scoreProcessor.Mode.Value = scoringMode; @@ -85,19 +85,18 @@ namespace osu.Game.Tests.Rulesets.Scoring [TestCase(ScoringMode.Standardised, HitResult.LargeTickHit, HitResult.LargeTickHit, 575_000)] // (3 * 30) / (4 * 30) * 300_000 + (0 / 4) * 700_000 [TestCase(ScoringMode.Standardised, HitResult.SmallBonus, HitResult.SmallBonus, 1_000_030)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 10 (bonus points) [TestCase(ScoringMode.Standardised, HitResult.LargeBonus, HitResult.LargeBonus, 1_000_150)] // 1 * 300_000 + 700_000 (max combo 0) + 3 * 50 (bonus points) - [TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)] // (0 * 4 * 300) * (1 + 0 / 25) - [TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 156)] // (((3 * 50) / (4 * 300)) * 4 * 300) * (1 + 1 / 25) - [TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 312)] // (((3 * 100) / (4 * 300)) * 4 * 300) * (1 + 1 / 25) - [TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 594)] // (((3 * 200) / (4 * 350)) * 4 * 300) * (1 + 1 / 25) - [TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 936)] // (((3 * 300) / (4 * 300)) * 4 * 300) * (1 + 1 / 25) - [TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 936)] // (((3 * 350) / (4 * 350)) * 4 * 300) * (1 + 1 / 25) - [TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 0)] // (0 * 1 * 300) * (1 + 0 / 25) - [TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 225)] // (((3 * 10) / (4 * 10)) * 1 * 300) * (1 + 0 / 25) - [TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] // (0 * 4 * 300) * (1 + 0 / 25) - [TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 936)] // (((3 * 50) / (4 * 50)) * 4 * 300) * (1 + 1 / 25) - // TODO: The following two cases don't match expectations currently (a single hit is registered in acc portion when it shouldn't be). See https://github.com/ppy/osu/issues/12604. - [TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 330)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 10 (bonus points) - [TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 450)] // (1 * 1 * 300) * (1 + 0 / 25) + 3 * 50 (bonus points) + [TestCase(ScoringMode.Classic, HitResult.Miss, HitResult.Great, 0)] + [TestCase(ScoringMode.Classic, HitResult.Meh, HitResult.Great, 68)] + [TestCase(ScoringMode.Classic, HitResult.Ok, HitResult.Great, 81)] + [TestCase(ScoringMode.Classic, HitResult.Good, HitResult.Perfect, 109)] + [TestCase(ScoringMode.Classic, HitResult.Great, HitResult.Great, 149)] + [TestCase(ScoringMode.Classic, HitResult.Perfect, HitResult.Perfect, 149)] + [TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, HitResult.SmallTickHit, 9)] + [TestCase(ScoringMode.Classic, HitResult.SmallTickHit, HitResult.SmallTickHit, 15)] + [TestCase(ScoringMode.Classic, HitResult.LargeTickMiss, HitResult.LargeTickHit, 0)] + [TestCase(ScoringMode.Classic, HitResult.LargeTickHit, HitResult.LargeTickHit, 149)] + [TestCase(ScoringMode.Classic, HitResult.SmallBonus, HitResult.SmallBonus, 18)] + [TestCase(ScoringMode.Classic, HitResult.LargeBonus, HitResult.LargeBonus, 18)] public void TestFourVariousResultsOneMiss(ScoringMode scoringMode, HitResult hitResult, HitResult maxResult, int expectedScore) { var minResult = new TestJudgement(hitResult).MinResult; @@ -129,8 +128,8 @@ namespace osu.Game.Tests.Rulesets.Scoring /// [TestCase(ScoringMode.Standardised, HitResult.SmallTickHit, 978_571)] // (3 * 10 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000 [TestCase(ScoringMode.Standardised, HitResult.SmallTickMiss, 914_286)] // (3 * 0 + 100) / (4 * 10 + 100) * 300_000 + (1 / 1) * 700_000 - [TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 279)] // (((3 * 10 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25) - [TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 214)] // (((3 * 0 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25) + [TestCase(ScoringMode.Classic, HitResult.SmallTickHit, 69)] // (((3 * 10 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25) + [TestCase(ScoringMode.Classic, HitResult.SmallTickMiss, 60)] // (((3 * 0 + 100) / (4 * 10 + 100)) * 1 * 300) * (1 + 0 / 25) public void TestSmallTicksAccuracy(ScoringMode scoringMode, HitResult hitResult, int expectedScore) { IEnumerable hitObjects = Enumerable From ce1912781e8b7144fbf4310031e4263636b0178e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 16:40:17 +0200 Subject: [PATCH 776/961] Add extension point for ruleset-specific beatmap setup sections --- osu.Game/Rulesets/Ruleset.cs | 7 +++++ .../Screens/Edit/Setup/RulesetSetupSection.cs | 20 ++++++++++++++ osu.Game/Screens/Edit/Setup/SetupScreen.cs | 27 ++++++++++++------- osu.Game/Screens/Edit/Setup/SetupSection.cs | 7 ++--- 4 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 80be61ead1..0a537f2442 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -28,6 +28,7 @@ using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Testing; using osu.Game.Extensions; using osu.Game.Rulesets.Filter; +using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; namespace osu.Game.Rulesets @@ -315,5 +316,11 @@ namespace osu.Game.Rulesets /// [CanBeNull] public virtual IRulesetFilterCriteria CreateRulesetFilterCriteria() => null; + + /// + /// Can be overridden to add a ruleset-specific section to the editor beatmap setup screen. + /// + [CanBeNull] + public virtual RulesetSetupSection CreateEditorSetupSectionForRuleset() => null; } } diff --git a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs new file mode 100644 index 0000000000..9344d5b491 --- /dev/null +++ b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.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.Localisation; +using osu.Game.Rulesets; + +namespace osu.Game.Screens.Edit.Setup +{ + public abstract class RulesetSetupSection : SetupSection + { + public sealed override LocalisableString Title => $"{rulesetInfo.Name}-specific"; + + private readonly RulesetInfo rulesetInfo; + + protected RulesetSetupSection(RulesetInfo rulesetInfo) + { + this.rulesetInfo = rulesetInfo; + } + } +} diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 746cf38867..53ddb13d85 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics.Containers; @@ -21,22 +22,28 @@ namespace osu.Game.Screens.Edit.Setup } [BackgroundDependencyLoader] - private void load() + private void load(EditorBeatmap beatmap) { + var sectionsEnumerable = new List + { + new ResourcesSection(), + new MetadataSection(), + new DifficultySection(), + new ColoursSection(), + new DesignSection(), + }; + + var rulesetSpecificSection = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateEditorSetupSectionForRuleset(); + if (rulesetSpecificSection != null) + sectionsEnumerable.Add(rulesetSpecificSection); + AddRange(new Drawable[] { sections = new SetupScreenSectionsContainer { - FixedHeader = header, RelativeSizeAxes = Axes.Both, - Children = new SetupSection[] - { - new ResourcesSection(), - new MetadataSection(), - new DifficultySection(), - new ColoursSection(), - new DesignSection(), - } + ChildrenEnumerable = sectionsEnumerable, + FixedHeader = header }, }); } diff --git a/osu.Game/Screens/Edit/Setup/SetupSection.cs b/osu.Game/Screens/Edit/Setup/SetupSection.cs index 1f988d62e2..1dde6fb926 100644 --- a/osu.Game/Screens/Edit/Setup/SetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/SetupSection.cs @@ -12,9 +12,9 @@ using osuTK; namespace osu.Game.Screens.Edit.Setup { - internal abstract class SetupSection : Container + public abstract class SetupSection : Container { - private readonly FillFlowContainer flow; + private FillFlowContainer flow; /// /// Used to align some of the child s together to achieve a grid-like look. @@ -31,7 +31,8 @@ namespace osu.Game.Screens.Edit.Setup public abstract LocalisableString Title { get; } - protected SetupSection() + [BackgroundDependencyLoader] + private void load() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; From a2d2ed2ef68565a72b3560e81ad3957500d2afa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 16:49:27 +0200 Subject: [PATCH 777/961] Add stack leniency setting for osu! --- .../Edit/Setup/OsuSetupSection.cs | 52 +++++++++++++++++++ osu.Game.Rulesets.Osu/OsuRuleset.cs | 4 ++ 2 files changed, 56 insertions(+) create mode 100644 osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs diff --git a/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs new file mode 100644 index 0000000000..8cb778a2e1 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Edit/Setup/OsuSetupSection.cs @@ -0,0 +1,52 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Screens.Edit.Setup; + +namespace osu.Game.Rulesets.Osu.Edit.Setup +{ + public class OsuSetupSection : RulesetSetupSection + { + private LabelledSliderBar stackLeniency; + + public OsuSetupSection() + : base(new OsuRuleset().RulesetInfo) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new[] + { + stackLeniency = new LabelledSliderBar + { + Label = "Stack Leniency", + Description = "In play mode, osu! automatically stacks notes which occur at the same location. Increasing this value means it is more likely to snap notes of further time-distance.", + Current = new BindableFloat(Beatmap.BeatmapInfo.StackLeniency) + { + Default = 0.7f, + MinValue = 0, + MaxValue = 1, + Precision = 0.1f + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + stackLeniency.Current.BindValueChanged(_ => updateBeatmap()); + } + + private void updateBeatmap() + { + Beatmap.BeatmapInfo.StackLeniency = stackLeniency.Current.Value; + } + } +} diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index b13cdff1ec..97af7d28af 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -30,9 +30,11 @@ using osu.Game.Skinning; using System; using System.Linq; using osu.Framework.Extensions.EnumExtensions; +using osu.Game.Rulesets.Osu.Edit.Setup; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Skinning.Legacy; using osu.Game.Rulesets.Osu.Statistics; +using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; namespace osu.Game.Rulesets.Osu @@ -305,5 +307,7 @@ namespace osu.Game.Rulesets.Osu } }; } + + public override RulesetSetupSection CreateEditorSetupSectionForRuleset() => new OsuSetupSection(); } } From 565f147a5c631a97dbddbcac76485104cff8ec03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 22 Aug 2021 17:40:11 +0200 Subject: [PATCH 778/961] Add special style setting for osu!mania --- .../Edit/Setup/ManiaSetupSection.cs | 45 +++++++++++++++++++ osu.Game.Rulesets.Mania/ManiaRuleset.cs | 4 ++ 2 files changed, 49 insertions(+) create mode 100644 osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs diff --git a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs new file mode 100644 index 0000000000..d0b32a7268 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.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.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Screens.Edit.Setup; + +namespace osu.Game.Rulesets.Mania.Edit.Setup +{ + public class ManiaSetupSection : RulesetSetupSection + { + private LabelledSwitchButton specialStyle; + + public ManiaSetupSection() + : base(new ManiaRuleset().RulesetInfo) + { + } + + [BackgroundDependencyLoader] + private void load() + { + Children = new Drawable[] + { + specialStyle = new LabelledSwitchButton + { + Label = "Use special (N+1) style", + Current = { Value = Beatmap.BeatmapInfo.SpecialStyle } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + specialStyle.Current.BindValueChanged(_ => updateBeatmap()); + } + + private void updateBeatmap() + { + Beatmap.BeatmapInfo.SpecialStyle = specialStyle.Current.Value; + } + } +} diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index f4b6e10af4..5ba1e2e6c3 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -27,11 +27,13 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Game.Rulesets.Mania.Difficulty; using osu.Game.Rulesets.Mania.Edit; +using osu.Game.Rulesets.Mania.Edit.Setup; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Skinning.Legacy; using osu.Game.Rulesets.Scoring; using osu.Game.Skinning; using osu.Game.Scoring; +using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Ranking.Statistics; namespace osu.Game.Rulesets.Mania @@ -390,6 +392,8 @@ namespace osu.Game.Rulesets.Mania { return new ManiaFilterCriteria(); } + + public override RulesetSetupSection CreateEditorSetupSectionForRuleset() => new ManiaSetupSection(); } public enum PlayfieldType From 000b85a860cb4e6f2f8cf12884fdf85adf1799aa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 17:56:56 +0900 Subject: [PATCH 779/961] Add GH Actions workflow for diffcalc checks --- .github/workflows/test-diffcalc.yml | 150 ++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 .github/workflows/test-diffcalc.yml diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml new file mode 100644 index 0000000000..b703c97735 --- /dev/null +++ b/.github/workflows/test-diffcalc.yml @@ -0,0 +1,150 @@ +name: Diffcalc Consistency Checks +on: + issue_comment: + types: [ created ] + +env: + DB_USER: root + DB_HOST: 127.0.0.1 + CONCURRENCY: 4 + ALLOW_DOWNLOAD: 1 + SAVE_DOWNLOADED: 1 + +jobs: + diffcalc: + name: Diffcalc + runs-on: ubuntu-latest + + if: | + contains(github.event.comment.html_url, '/pull/') && + contains(github.event.comment.body, '!pp check') && + ${{ github.event.comment.author_association == 'MEMBER' }} + + + strategy: + fail-fast: false + matrix: + ruleset: + - { name: osu, id: 0 } + - { name: taiko, id: 1 } + - { name: catch, id: 2 } + - { name: mania, id: 3 } + + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + steps: + - name: Verify MySQL connection from host + run: | + sudo apt-get install -y mysql-client + mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "SHOW DATABASES" + + - name: Create directory structure + run: | + mkdir -p $GITHUB_WORKSPACE/master/ + mkdir -p $GITHUB_WORKSPACE/pr/ + + # Checkout osu + - name: Checkout osu (master) + uses: actions/checkout@v2 + with: + repository: ppy/osu + path: 'master/osu' + - name: Checkout osu (pr) + uses: actions/checkout@v2 + with: + path: 'pr/osu' + + # Checkout osu-difficulty-calculator + - name: Checkout osu-difficulty-calculator (master) + uses: actions/checkout@v2 + with: + repository: ppy/osu-difficulty-calculator + path: 'master/osu-difficulty-calculator' + - name: Checkout osu-difficulty-calculator (pr) + uses: actions/checkout@v2 + with: + repository: ppy/osu-difficulty-calculator + path: 'pr/osu-difficulty-calculator' + + - name: Install .NET 5.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "5.0.x" + + # Sanity checks to make sure diffcalc is not run when incompatible. + - name: Build diffcalc (master) + run: | + cd $GITHUB_WORKSPACE/master/osu-difficulty-calculator + ./UseLocalOsu.sh + dotnet build + - name: Build diffcalc (pr) + run: | + cd $GITHUB_WORKSPACE/pr/osu-difficulty-calculator + ./UseLocalOsu.sh + dotnet build + + # Initial data imports + - name: Download + import data + run: | + PERFORMANCE_DATA_NAME=$(date +'%Y_%m_01_performance_${{ matrix.ruleset.name }}_random') + BEATMAPS_DATA_NAME=$(date +'%Y_%m_01_osu_files') + + # Set env variable for further steps. + echo "BEATMAPS_PATH=$GITHUB_WORKSPACE/$BEATMAPS_DATA_NAME" >> $GITHUB_ENV + + cd $GITHUB_WORKSPACE + + wget https://data.ppy.sh/$PERFORMANCE_DATA_NAME.tar.bz2 + wget https://data.ppy.sh/$BEATMAPS_DATA_NAME.tar.bz2 + tar -xf $PERFORMANCE_DATA_NAME.tar.bz2 + tar -xf $BEATMAPS_DATA_NAME.tar.bz2 + + cd $GITHUB_WORKSPACE/$PERFORMANCE_DATA_NAME + + mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_master" + mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e "CREATE DATABASE osu_pr" + + cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_master + cat *.sql | mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} --database=osu_pr + + # Run diffcalc + - name: Run diffcalc (master) + env: + DB_NAME: osu_master + run: | + cd $GITHUB_WORKSPACE/master/osu-difficulty-calculator/osu.Server.DifficultyCalculator + dotnet run -c:Release -- all -m ${{ matrix.ruleset.id }} -ac -c ${{ env.CONCURRENCY }} + - name: Run diffcalc (pr) + env: + DB_NAME: osu_pr + run: | + cd $GITHUB_WORKSPACE/pr/osu-difficulty-calculator/osu.Server.DifficultyCalculator + dotnet run -c:Release -- all -m ${{ matrix.ruleset.id }} -ac -c ${{ env.CONCURRENCY }} + + # Print diffs + - name: Print diffs + run: | + mysql --host ${{ env.DB_HOST }} -u${{ env.DB_USER }} -e " + SELECT + m.beatmap_id, + m.mods, + m.diff_unified as `sr_master`, + p.diff_unified as `sr_pr`, + (p.diff_unified - m.diff_unified) as `diff` + FROM osu_master.osu_beatmap_difficulty m + JOIN osu_pr.osu_beatmap_difficulty p + ON m.beatmap_id = p.beatmap_id + AND m.mode = p.mode + AND m.mods = p.mods + WHERE abs(m.diff_unified - p.diff_unified) > 0.1 + ORDER BY abs(m.diff_unified - p.diff_unified) + DESC;" + + # Todo: Run ppcalc \ No newline at end of file From 176c414c112e1321a65fde03b78ecf72a479285a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 18:10:16 +0900 Subject: [PATCH 780/961] More accurate data retrieval --- .github/workflows/test-diffcalc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index b703c97735..3d80f08ebf 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -93,8 +93,8 @@ jobs: # Initial data imports - name: Download + import data run: | - PERFORMANCE_DATA_NAME=$(date +'%Y_%m_01_performance_${{ matrix.ruleset.name }}_random') - BEATMAPS_DATA_NAME=$(date +'%Y_%m_01_osu_files') + PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_random | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') + BEATMAPS_DATA_NAME=$(curl https://data.ppy.sh/ | grep osu_files | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') # Set env variable for further steps. echo "BEATMAPS_PATH=$GITHUB_WORKSPACE/$BEATMAPS_DATA_NAME" >> $GITHUB_ENV From b8ada31d7de0b4fa47abd50a84d83a67e409eec5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 18:47:15 +0900 Subject: [PATCH 781/961] Match against individual rulesets --- .github/workflows/test-diffcalc.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 3d80f08ebf..48e1e238c1 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -1,3 +1,8 @@ +# Listens to new PR comments containing "!pp check", and runs diffcalc across the PR and master to produce a table of differences. +# Usage: +# !pp check 0 : Runs only the osu! ruleset +# !pp check 0 1 : Runs the osu! and taiko rulesets. + name: Diffcalc Consistency Checks on: issue_comment: @@ -18,8 +23,8 @@ jobs: if: | contains(github.event.comment.html_url, '/pull/') && contains(github.event.comment.body, '!pp check') && - ${{ github.event.comment.author_association == 'MEMBER' }} - + ${{ github.event.comment.author_association == 'MEMBER' }} && + contains(github.event.comment.body, ${{ matrix.ruleset.id }}) strategy: fail-fast: false From 789c108e8d426fba356d4f424427f558c2b19ec8 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 18:56:56 +0900 Subject: [PATCH 782/961] Fix if condition --- .github/workflows/test-diffcalc.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 48e1e238c1..64ffa84c5e 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -23,8 +23,7 @@ jobs: if: | contains(github.event.comment.html_url, '/pull/') && contains(github.event.comment.body, '!pp check') && - ${{ github.event.comment.author_association == 'MEMBER' }} && - contains(github.event.comment.body, ${{ matrix.ruleset.id }}) + ${{ github.event.comment.author_association == 'MEMBER' }} strategy: fail-fast: false @@ -34,6 +33,10 @@ jobs: - { name: taiko, id: 1 } - { name: catch, id: 2 } - { name: mania, id: 3 } + isValidRuleset: + - contains(github.event.comment.body, ${{ matrix.ruleset.id }}) + exclude: + - isValidRuleset: false services: mysql: From 33dcb4915b28e36e354151eb8e7ee929695bddd7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 19:12:41 +0900 Subject: [PATCH 783/961] Revert "Fix if condition" This reverts commit 789c108e8d426fba356d4f424427f558c2b19ec8. --- .github/workflows/test-diffcalc.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 64ffa84c5e..48e1e238c1 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -23,7 +23,8 @@ jobs: if: | contains(github.event.comment.html_url, '/pull/') && contains(github.event.comment.body, '!pp check') && - ${{ github.event.comment.author_association == 'MEMBER' }} + ${{ github.event.comment.author_association == 'MEMBER' }} && + contains(github.event.comment.body, ${{ matrix.ruleset.id }}) strategy: fail-fast: false @@ -33,10 +34,6 @@ jobs: - { name: taiko, id: 1 } - { name: catch, id: 2 } - { name: mania, id: 3 } - isValidRuleset: - - contains(github.event.comment.body, ${{ matrix.ruleset.id }}) - exclude: - - isValidRuleset: false services: mysql: From 54389561aaefd5b1f69f1aa5b360260ba1328676 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 19:12:55 +0900 Subject: [PATCH 784/961] Revert "Match against individual rulesets" This reverts commit b8ada31d7de0b4fa47abd50a84d83a67e409eec5. --- .github/workflows/test-diffcalc.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 48e1e238c1..3d80f08ebf 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -1,8 +1,3 @@ -# Listens to new PR comments containing "!pp check", and runs diffcalc across the PR and master to produce a table of differences. -# Usage: -# !pp check 0 : Runs only the osu! ruleset -# !pp check 0 1 : Runs the osu! and taiko rulesets. - name: Diffcalc Consistency Checks on: issue_comment: @@ -23,8 +18,8 @@ jobs: if: | contains(github.event.comment.html_url, '/pull/') && contains(github.event.comment.body, '!pp check') && - ${{ github.event.comment.author_association == 'MEMBER' }} && - contains(github.event.comment.body, ${{ matrix.ruleset.id }}) + ${{ github.event.comment.author_association == 'MEMBER' }} + strategy: fail-fast: false From 893a4d43657ab4d335d951cee8e22708d00e09b4 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 19:23:55 +0900 Subject: [PATCH 785/961] Fix incorrect quoting --- .github/workflows/test-diffcalc.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 3d80f08ebf..1e5c033a67 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -135,9 +135,9 @@ jobs: SELECT m.beatmap_id, m.mods, - m.diff_unified as `sr_master`, - p.diff_unified as `sr_pr`, - (p.diff_unified - m.diff_unified) as `diff` + m.diff_unified as 'sr_master', + p.diff_unified as 'sr_pr', + (p.diff_unified - m.diff_unified) as 'diff' FROM osu_master.osu_beatmap_difficulty m JOIN osu_pr.osu_beatmap_difficulty p ON m.beatmap_id = p.beatmap_id From c6d71e1ae8bb7d3862abd063db7e285f311e4d2d Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 20:10:17 +0900 Subject: [PATCH 786/961] Add back ruleset check --- .github/workflows/test-diffcalc.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 1e5c033a67..ab7107f594 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -20,7 +20,6 @@ jobs: contains(github.event.comment.body, '!pp check') && ${{ github.event.comment.author_association == 'MEMBER' }} - strategy: fail-fast: false matrix: @@ -40,6 +39,12 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: + - name: Verify ruleset + if: contains(github.event.comment.body, matrix.ruleset.id) == false + run: | + echo "${{ github.event.comment.body }} doesn't contain ${{ matrix.ruleset.id }}" + exit 1 + - name: Verify MySQL connection from host run: | sudo apt-get install -y mysql-client From 1f7f8bb18992d1a8a558eb432acdc1a7e55e30ec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 20:13:33 +0900 Subject: [PATCH 787/961] Add description to workflow --- .github/workflows/test-diffcalc.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index ab7107f594..c6b2f254c8 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -1,3 +1,9 @@ +# Listens for new PR comments containing !pp check [id], and runs a diffcalc comparison against master. +# Usage: +# !pp check 0 | Runs only the osu! ruleset. +# !pp check 0 2 | Runs only the osu! and catch rulesets. +# + name: Diffcalc Consistency Checks on: issue_comment: From 88158b79f8e5ad2154fa1efd0f89e10532421600 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 3 Sep 2021 20:37:38 +0900 Subject: [PATCH 788/961] Change to using top scores --- .github/workflows/test-diffcalc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index c6b2f254c8..3bec11928f 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -104,7 +104,7 @@ jobs: # Initial data imports - name: Download + import data run: | - PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_random | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') + PERFORMANCE_DATA_NAME=$(curl https://data.ppy.sh/ | grep performance_${{ matrix.ruleset.name }}_top | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') BEATMAPS_DATA_NAME=$(curl https://data.ppy.sh/ | grep osu_files | tail -1 | awk -F "\"" '{print $2}' | sed 's/\.tar\.bz2//g') # Set env variable for further steps. From 16beb2c90c1884d8829f52cb92142c06498d3b00 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 15:35:46 +0900 Subject: [PATCH 789/961] Expose more pieces of `TabletSettings` --- .../Settings/Sections/Input/TabletAreaSelection.cs | 8 +++++--- .../Overlays/Settings/Sections/Input/TabletSettings.cs | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 412889d210..e18cf7e1c2 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -17,6 +17,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public class TabletAreaSelection : CompositeDrawable { + public bool IsWithinBounds { get; private set; } + private readonly ITabletHandler handler; private Container tabletContainer; @@ -171,10 +173,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input var usableSsdq = usableAreaContainer.ScreenSpaceDrawQuad; - bool isWithinBounds = tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.TopLeft + new Vector2(1)) && - tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.BottomRight - new Vector2(1)); + IsWithinBounds = tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.TopLeft + new Vector2(1)) && + tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.BottomRight - new Vector2(1)); - usableFill.FadeColour(isWithinBounds ? colour.Blue : colour.RedLight, 100); + usableFill.FadeColour(IsWithinBounds ? colour.Blue : colour.RedLight, 100); } protected override void Update() diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs index b8b86d9069..8c60e81fb5 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs @@ -20,6 +20,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input { public class TabletSettings : SettingsSubsection { + public TabletAreaSelection AreaSelection { get; private set; } + private readonly ITabletHandler tabletHandler; private readonly Bindable enabled = new BindableBool(true); @@ -121,7 +123,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input Direction = FillDirection.Vertical, Children = new Drawable[] { - new TabletAreaSelection(tabletHandler) + AreaSelection = new TabletAreaSelection(tabletHandler) { RelativeSizeAxes = Axes.X, Height = 300, From 8d44f059ec952080516bb6f811676404bde64ebb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 15:35:54 +0900 Subject: [PATCH 790/961] Add test coverage of failing validity checks --- .../Settings/TestSceneTabletSettings.cs | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index da474a64ba..0202393973 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -2,11 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Handlers.Tablet; -using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Overlays; using osu.Game.Overlays.Settings.Sections.Input; @@ -17,22 +16,34 @@ namespace osu.Game.Tests.Visual.Settings [TestFixture] public class TestSceneTabletSettings : OsuTestScene { - [BackgroundDependencyLoader] - private void load(GameHost host) - { - var tabletHandler = new TestTabletHandler(); + private TestTabletHandler tabletHandler; + private TabletSettings settings; - AddRange(new Drawable[] + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create settings", () => { - new TabletSettings(tabletHandler) + tabletHandler = new TestTabletHandler(); + + Children = new Drawable[] { - RelativeSizeAxes = Axes.None, - Width = SettingsPanel.PANEL_WIDTH, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - } + settings = new TabletSettings(tabletHandler) + { + RelativeSizeAxes = Axes.None, + Width = SettingsPanel.PANEL_WIDTH, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + } + }; }); + AddStep("set square size", () => tabletHandler.SetTabletSize(new Vector2(100, 100))); + } + + [Test] + public void TestVariousTabletSizes() + { AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100))); AddStep("Test with square tablet", () => tabletHandler.SetTabletSize(new Vector2(300, 300))); AddStep("Test with tall tablet", () => tabletHandler.SetTabletSize(new Vector2(100, 300))); @@ -40,6 +51,24 @@ namespace osu.Game.Tests.Visual.Settings AddStep("Test no tablet present", () => tabletHandler.SetTabletSize(Vector2.Zero)); } + [Test] + public void TestValidAfterRotation() + { + AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + AddStep("rotate 90", () => tabletHandler.Rotation.Value = 90); + AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + AddStep("rotate 180", () => tabletHandler.Rotation.Value = 180); + AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + AddStep("rotate 360", () => tabletHandler.Rotation.Value = 360); + AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); + AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + } + public class TestTabletHandler : ITabletHandler { public Bindable AreaOffset { get; } = new Bindable(); From 66daa553de2eac46f35d511a34ff959d1b3ab9c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 19:34:55 +0900 Subject: [PATCH 791/961] Fix bounds check running too early causing tablet area to show incorrect validity --- .../Overlays/Settings/Sections/Input/TabletAreaSelection.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index e18cf7e1c2..4f27a2da70 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -131,9 +131,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input rotation.BindTo(handler.Rotation); rotation.BindValueChanged(val => { - tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint); - usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint) - .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint); + tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint) + .OnComplete(_ => checkBounds()); // required as we are using SSDQ. }, true); tablet.BindTo(handler.Tablet); From 7b26e480e6492348bb0c91b65a20c9f3d9cbfcf5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 22:55:14 +0900 Subject: [PATCH 792/961] Add extended tests --- .../Settings/TestSceneTabletSettings.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 0202393973..a854bec1a9 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -1,9 +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 NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Testing; using osu.Framework.Utils; @@ -57,15 +59,27 @@ namespace osu.Game.Tests.Visual.Settings AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); AddStep("rotate 90", () => tabletHandler.Rotation.Value = 90); - AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + ensureValid(); AddStep("rotate 180", () => tabletHandler.Rotation.Value = 180); - AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + ensureValid(); + + AddStep("rotate 270", () => tabletHandler.Rotation.Value = 270); + + ensureValid(); AddStep("rotate 360", () => tabletHandler.Rotation.Value = 360); - AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); + + ensureValid(); AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); + ensureValid(); + } + + private void ensureValid() + { + AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType().All(c => !c.Transforms.Any())); AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); } From 94b34a5474cf625b274f3b6f84477417b62ee179 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 23:19:05 +0900 Subject: [PATCH 793/961] Add test coverage of invalid cases too --- .../Settings/TestSceneTabletSettings.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index a854bec1a9..d5bcbc5fd9 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Settings } [Test] - public void TestValidAfterRotation() + public void TestRotationValidity() { AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); @@ -75,6 +75,22 @@ namespace osu.Game.Tests.Visual.Settings AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); ensureValid(); + + AddStep("rotate 0", () => tabletHandler.Rotation.Value = 45); + ensureInvalid(); + + AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); + ensureValid(); + } + + [Test] + public void TestOffsetValidity() + { + ensureValid(); + AddStep("move right", () => tabletHandler.AreaOffset.Value = Vector2.Zero); + ensureInvalid(); + AddStep("move back", () => tabletHandler.AreaOffset.Value = tabletHandler.AreaSize.Value / 2); + ensureValid(); } private void ensureValid() @@ -83,6 +99,12 @@ namespace osu.Game.Tests.Visual.Settings AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); } + private void ensureInvalid() + { + AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType().All(c => !c.Transforms.Any())); + AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds); + } + public class TestTabletHandler : ITabletHandler { public Bindable AreaOffset { get; } = new Bindable(); From 4fb3a1d64162866cb973efeedbe456af2eba8603 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 4 Sep 2021 23:08:35 +0900 Subject: [PATCH 794/961] Update check to inflate in the correct direct Also handles previously unhandled edge cases by comparing all four corners, instead of only two. --- .../Sections/Input/TabletAreaSelection.cs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index 4f27a2da70..d12052b24d 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -4,10 +4,13 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.MatrixExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Handlers.Tablet; +using osu.Framework.Utils; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osuTK; @@ -131,9 +134,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input rotation.BindTo(handler.Rotation); rotation.BindValueChanged(val => { - usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint); - tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint) - .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint) + .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint); }, true); tablet.BindTo(handler.Tablet); @@ -171,10 +174,22 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (tablet.Value == null) return; - var usableSsdq = usableAreaContainer.ScreenSpaceDrawQuad; + // All of this manual logic is just to get around floating point issues when doing a contains check on the screen quads. + // This is best effort, as it's only used for display purposes. If we need for anything more, manual math on the raw values should be preferred. + var containerQuad = tabletContainer.ScreenSpaceDrawQuad.AABBFloat.Inflate(1); + var usableAreaQuad = Quad.FromRectangle(usableAreaContainer.ScreenSpaceDrawQuad.AABBFloat); - IsWithinBounds = tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.TopLeft + new Vector2(1)) && - tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.BottomRight - new Vector2(1)); + var matrix = Matrix3.Identity; + MatrixExtensions.TranslateFromLeft(ref matrix, usableAreaQuad.Centre); + MatrixExtensions.RotateFromLeft(ref matrix, MathUtils.DegreesToRadians(rotation.Value)); + MatrixExtensions.TranslateFromLeft(ref matrix, -usableAreaQuad.Centre); + usableAreaQuad *= matrix; + + IsWithinBounds = + containerQuad.Contains(usableAreaQuad.TopLeft) && + containerQuad.Contains(usableAreaQuad.TopRight) && + containerQuad.Contains(usableAreaQuad.BottomLeft) && + containerQuad.Contains(usableAreaQuad.BottomRight); usableFill.FadeColour(IsWithinBounds ? colour.Blue : colour.RedLight, 100); } From 1a90fb1ef341d3d72a75bc29c6e2410967b67800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 4 Sep 2021 19:52:42 +0200 Subject: [PATCH 795/961] Fix cached property being assigned twice --- osu.Game/Screens/Edit/Setup/SetupScreen.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 53ddb13d85..38fcfc5d2f 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -11,7 +11,7 @@ namespace osu.Game.Screens.Edit.Setup public class SetupScreen : EditorRoundedScreen { [Cached] - private SectionsContainer sections = new SectionsContainer(); + private SectionsContainer sections { get; } = new SetupScreenSectionsContainer(); [Cached] private SetupScreenHeader header = new SetupScreenHeader(); @@ -37,15 +37,12 @@ namespace osu.Game.Screens.Edit.Setup if (rulesetSpecificSection != null) sectionsEnumerable.Add(rulesetSpecificSection); - AddRange(new Drawable[] + Add(sections.With(s => { - sections = new SetupScreenSectionsContainer - { - RelativeSizeAxes = Axes.Both, - ChildrenEnumerable = sectionsEnumerable, - FixedHeader = header - }, - }); + s.RelativeSizeAxes = Axes.Both; + s.ChildrenEnumerable = sectionsEnumerable; + s.FixedHeader = header; + })); } private class SetupScreenSectionsContainer : SectionsContainer From 4c006333e0298f0998a1a0044df978c521e52dec Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 4 Sep 2021 19:42:14 +0100 Subject: [PATCH 796/961] add /chat command --- osu.Game/Online/Chat/ChannelManager.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 1937019ef6..fb8c90a80c 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -256,8 +256,21 @@ namespace osu.Game.Online.Chat JoinChannel(channel); break; + case "chat": + if (string.IsNullOrWhiteSpace(content)) + { + target.AddNewMessages(new ErrorMessage("Usage: /chat [user]")); + break; + } + + var request = new GetUserRequest(content); + request.Success += u => OpenPrivateChannel(u); + request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); + api.Queue(request); + break; + case "help": - target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /np")); + target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /chat [user], /np")); break; default: From ea3be927d7f5c8071bacded41a021340b6a6c5e2 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 4 Sep 2021 20:02:10 +0100 Subject: [PATCH 797/961] convert to method group --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index fb8c90a80c..f58f1ff40c 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -264,7 +264,7 @@ namespace osu.Game.Online.Chat } var request = new GetUserRequest(content); - request.Success += u => OpenPrivateChannel(u); + request.Success += OpenPrivateChannel; request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); api.Queue(request); break; From f76f12d361a97238797b7115003bbfc9f79f5272 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 11:14:28 +0900 Subject: [PATCH 798/961] Fix incorrect test step name Co-authored-by: PercyDan <50285552+PercyDan54@users.noreply.github.com> --- osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index d5bcbc5fd9..49d6b7033e 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Settings AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); ensureValid(); - AddStep("rotate 0", () => tabletHandler.Rotation.Value = 45); + AddStep("rotate 45", () => tabletHandler.Rotation.Value = 45); ensureInvalid(); AddStep("rotate 0", () => tabletHandler.Rotation.Value = 0); From 1d23ac0f2db355914a45affc9491970eeec39248 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 12:54:21 +0900 Subject: [PATCH 799/961] Initial clean up pass on notification logic --- osu.Game/Graphics/UserInterface/HoverSounds.cs | 3 +-- osu.Game/Overlays/NotificationOverlay.cs | 9 +++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index c0ef5cb3fc..7db1efc75f 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -6,7 +6,6 @@ using osu.Framework.Audio; using osu.Framework.Audio.Sample; using osu.Framework.Extensions; using osu.Framework.Graphics; -using osu.Game.Configuration; using osu.Framework.Utils; namespace osu.Game.Graphics.UserInterface @@ -28,7 +27,7 @@ namespace osu.Game.Graphics.UserInterface } [BackgroundDependencyLoader] - private void load(AudioManager audio, SessionStatics statics) + private void load(AudioManager audio) { sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover"); diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2175e17da9..f5b0bf2a7d 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -98,14 +98,16 @@ namespace osu.Game.Overlays private int runningDepth; - private void notificationClosed() => updateCounts(); - private readonly Scheduler postScheduler = new Scheduler(); public override bool IsPresent => base.IsPresent || postScheduler.HasPendingTasks; private bool processingPosts = true; + /// + /// Post a new notification for display. + /// + /// The notification to display. public void Post(Notification notification) => postScheduler.Add(() => { ++runningDepth; @@ -129,6 +131,7 @@ namespace osu.Game.Overlays protected override void Update() { base.Update(); + if (processingPosts) postScheduler.Update(); } @@ -151,6 +154,8 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } + private void notificationClosed() => updateCounts(); + private void updateCounts() { UnreadCount.Value = sections.Select(c => c.UnreadCount).Sum(); From 473e15e8f3ba1a35419bc0bbb0f72034715a2e80 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:22:37 +0900 Subject: [PATCH 800/961] Add debounce to notification sample playback logic --- osu.Game/Overlays/NotificationOverlay.cs | 25 +++++++++++++++- .../Overlays/Notifications/Notification.cs | 29 ++++--------------- .../Notifications/NotificationSection.cs | 7 +---- .../Notifications/ProgressNotification.cs | 4 +-- .../Notifications/SimpleErrorNotification.cs | 2 +- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index f5b0bf2a7d..fcb8692010 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -9,6 +9,7 @@ using osu.Game.Overlays.Notifications; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Localisation; using osu.Framework.Threading; @@ -29,6 +30,9 @@ namespace osu.Game.Overlays private FlowContainer sections; + [Resolved] + private AudioManager audio { get; set; } + [BackgroundDependencyLoader] private void load() { @@ -104,6 +108,8 @@ namespace osu.Game.Overlays private bool processingPosts = true; + private double? lastSamplePlayback; + /// /// Post a new notification for display. /// @@ -126,6 +132,7 @@ namespace osu.Game.Overlays Show(); updateCounts(); + playDebouncedSample(notification.PopInSampleName); }); protected override void Update() @@ -154,7 +161,23 @@ namespace osu.Game.Overlays this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint); } - private void notificationClosed() => updateCounts(); + private void notificationClosed() + { + updateCounts(); + + // this debounce is currently shared between popin/popout sounds, which means one could potentially not play when the user is expecting it. + // popout is constant across all notification types, and should therefore be handled using playback concurrency instead, but seems broken at the moment. + playDebouncedSample("UI/overlay-pop-out"); + } + + private void playDebouncedSample(string sampleName) + { + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > 50) + { + audio.Samples.Get(sampleName)?.Play(); + lastSamplePlayback = Time.Current; + } + } private void updateCounts() { diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index d1a97c74b2..44203e8ee7 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -3,20 +3,18 @@ using System; using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; -using osu.Game.Graphics; -using osuTK; -using osuTK.Graphics; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.Notifications { @@ -42,10 +40,7 @@ namespace osu.Game.Overlays.Notifications /// public virtual bool DisplayOnTop => true; - private Sample samplePopIn; - private Sample samplePopOut; - protected virtual string PopInSampleName => "UI/notification-pop-in"; - protected virtual string PopOutSampleName => "UI/overlay-pop-out"; // TODO: replace with a unique sample? + public virtual string PopInSampleName => "UI/notification-pop-in"; protected NotificationLight Light; private readonly CloseButton closeButton; @@ -114,7 +109,7 @@ namespace osu.Game.Overlays.Notifications closeButton = new CloseButton { Alpha = 0, - Action = () => Close(), + Action = Close, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding @@ -127,13 +122,6 @@ namespace osu.Game.Overlays.Notifications }); } - [BackgroundDependencyLoader] - private void load(AudioManager audio) - { - samplePopIn = audio.Samples.Get(PopInSampleName); - samplePopOut = audio.Samples.Get(PopOutSampleName); - } - protected override bool OnHover(HoverEvent e) { closeButton.FadeIn(75); @@ -158,8 +146,6 @@ namespace osu.Game.Overlays.Notifications { base.LoadComplete(); - samplePopIn?.Play(); - this.FadeInFromZero(200); NotificationContent.MoveToX(DrawSize.X); NotificationContent.MoveToX(0, 500, Easing.OutQuint); @@ -167,15 +153,12 @@ namespace osu.Game.Overlays.Notifications public bool WasClosed; - public virtual void Close(bool playSound = true) + public virtual void Close() { if (WasClosed) return; WasClosed = true; - if (playSound) - samplePopOut?.Play(); - Closed?.Invoke(); this.FadeOut(100); Expire(); diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 2316199049..a23ff07a64 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -110,12 +110,7 @@ namespace osu.Game.Overlays.Notifications private void clearAll() { - bool first = true; - notifications.Children.ForEach(c => - { - c.Close(first); - first = false; - }); + notifications.Children.ForEach(c => c.Close()); } protected override void Update() diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index 703c14af2b..3105ecd742 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -150,12 +150,12 @@ namespace osu.Game.Overlays.Notifications colourCancelled = colours.Red; } - public override void Close(bool playSound = true) + public override void Close() { switch (State) { case ProgressNotificationState.Cancelled: - base.Close(playSound); + base.Close(); break; case ProgressNotificationState.Active: diff --git a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs index 13c9c5a02d..faab4ed472 100644 --- a/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleErrorNotification.cs @@ -7,7 +7,7 @@ namespace osu.Game.Overlays.Notifications { public class SimpleErrorNotification : SimpleNotification { - protected override string PopInSampleName => "UI/error-notification-pop-in"; + public override string PopInSampleName => "UI/error-notification-pop-in"; public SimpleErrorNotification() { From ab1c64591f2a9b224cec05919606836edccd5c21 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:25:10 +0900 Subject: [PATCH 801/961] Move sample playback debounce time to central `const` --- .../Graphics/UserInterface/HoverSampleDebounceComponent.cs | 7 +------ osu.Game/OsuGameBase.cs | 5 +++++ osu.Game/Overlays/NotificationOverlay.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs index 55f43cfe46..1fd03a34e7 100644 --- a/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs +++ b/osu.Game/Graphics/UserInterface/HoverSampleDebounceComponent.cs @@ -15,11 +15,6 @@ namespace osu.Game.Graphics.UserInterface /// public abstract class HoverSampleDebounceComponent : CompositeDrawable { - /// - /// Length of debounce for hover sound playback, in milliseconds. - /// - public double HoverDebounceTime { get; } = 20; - private Bindable lastPlaybackTime; [BackgroundDependencyLoader] @@ -34,7 +29,7 @@ namespace osu.Game.Graphics.UserInterface if (e.HasAnyButtonPressed) return false; - bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime; + bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= OsuGameBase.SAMPLE_DEBOUNCE_TIME; if (enoughTimePassedSinceLastPlayback) { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 69f6bc1b7b..762216e93c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -56,6 +56,11 @@ namespace osu.Game public const int SAMPLE_CONCURRENCY = 6; + /// + /// Length of debounce (in milliseconds) for commonly occuring sample playbacks that could stack. + /// + public const int SAMPLE_DEBOUNCE_TIME = 20; + /// /// The maximum volume at which audio tracks should playback. This can be set lower than 1 to create some head-room for sound effects. /// diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index fcb8692010..8809dec642 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -172,7 +172,7 @@ namespace osu.Game.Overlays private void playDebouncedSample(string sampleName) { - if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > 50) + if (lastSamplePlayback == null || Time.Current - lastSamplePlayback > OsuGameBase.SAMPLE_DEBOUNCE_TIME) { audio.Samples.Get(sampleName)?.Play(); lastSamplePlayback = Time.Current; From 25420af078151b68146f8786911562869b39e7fd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:34:23 +0900 Subject: [PATCH 802/961] Rename method to drop redundant ruleset suffix --- osu.Game.Rulesets.Mania/ManiaRuleset.cs | 2 +- osu.Game.Rulesets.Osu/OsuRuleset.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 2 +- osu.Game/Screens/Edit/Setup/SetupScreen.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 5ba1e2e6c3..1f79dae280 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -393,7 +393,7 @@ namespace osu.Game.Rulesets.Mania return new ManiaFilterCriteria(); } - public override RulesetSetupSection CreateEditorSetupSectionForRuleset() => new ManiaSetupSection(); + public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection(); } public enum PlayfieldType diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index 97af7d28af..f4a93a571d 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -308,6 +308,6 @@ namespace osu.Game.Rulesets.Osu }; } - public override RulesetSetupSection CreateEditorSetupSectionForRuleset() => new OsuSetupSection(); + public override RulesetSetupSection CreateEditorSetupSection() => new OsuSetupSection(); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 0a537f2442..de62cf8d33 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -321,6 +321,6 @@ namespace osu.Game.Rulesets /// Can be overridden to add a ruleset-specific section to the editor beatmap setup screen. /// [CanBeNull] - public virtual RulesetSetupSection CreateEditorSetupSectionForRuleset() => null; + public virtual RulesetSetupSection CreateEditorSetupSection() => null; } } diff --git a/osu.Game/Screens/Edit/Setup/SetupScreen.cs b/osu.Game/Screens/Edit/Setup/SetupScreen.cs index 38fcfc5d2f..04767f1786 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreen.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreen.cs @@ -33,7 +33,7 @@ namespace osu.Game.Screens.Edit.Setup new DesignSection(), }; - var rulesetSpecificSection = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateEditorSetupSectionForRuleset(); + var rulesetSpecificSection = beatmap.BeatmapInfo.Ruleset?.CreateInstance()?.CreateEditorSetupSection(); if (rulesetSpecificSection != null) sectionsEnumerable.Add(rulesetSpecificSection); From e0ee2a553375e3ab7460ac3716b280ef577d04eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:34:57 +0900 Subject: [PATCH 803/961] Change section title to read better --- osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs index 9344d5b491..935842ff99 100644 --- a/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs +++ b/osu.Game/Screens/Edit/Setup/RulesetSetupSection.cs @@ -8,7 +8,7 @@ namespace osu.Game.Screens.Edit.Setup { public abstract class RulesetSetupSection : SetupSection { - public sealed override LocalisableString Title => $"{rulesetInfo.Name}-specific"; + public sealed override LocalisableString Title => $"Ruleset ({rulesetInfo.Name})"; private readonly RulesetInfo rulesetInfo; From 1a26658ba4d3ab18ce3661bb4f1ec4b8405d825d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:40:49 +0900 Subject: [PATCH 804/961] Add description for mania special style --- osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs index d0b32a7268..a206aafb8a 100644 --- a/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs +++ b/osu.Game.Rulesets.Mania/Edit/Setup/ManiaSetupSection.cs @@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Mania.Edit.Setup specialStyle = new LabelledSwitchButton { Label = "Use special (N+1) style", + Description = "Changes one column to act as a classic \"scratch\" or \"special\" column, which can be moved around by the user's skin (to the left/right/centre). Generally used in 5k (4+1) or 8key (7+1) configurations.", Current = { Value = Beatmap.BeatmapInfo.SpecialStyle } } }; From 6e4efdd1b11dde4ad43bcee7c1745a7374bf482e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 5 Sep 2021 13:40:58 +0900 Subject: [PATCH 805/961] Add test coverage for per-ruleset setup screens --- .../Visual/Editing/TestSceneSetupScreen.cs | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs index 9253023c9a..c3c803ff23 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneSetupScreen.cs @@ -4,8 +4,13 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Edit; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Beatmaps; +using osu.Game.Rulesets.Taiko; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; @@ -23,15 +28,31 @@ namespace osu.Game.Tests.Visual.Editing editorBeatmap = new EditorBeatmap(new OsuBeatmap()); } - [BackgroundDependencyLoader] - private void load() - { - Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + [Test] + public void TestOsu() => runForRuleset(new OsuRuleset().RulesetInfo); - Child = new SetupScreen + [Test] + public void TestTaiko() => runForRuleset(new TaikoRuleset().RulesetInfo); + + [Test] + public void TestCatch() => runForRuleset(new CatchRuleset().RulesetInfo); + + [Test] + public void TestMania() => runForRuleset(new ManiaRuleset().RulesetInfo); + + private void runForRuleset(RulesetInfo rulesetInfo) + { + AddStep("create screen", () => { - State = { Value = Visibility.Visible }, - }; + editorBeatmap.BeatmapInfo.Ruleset = rulesetInfo; + + Beatmap.Value = CreateWorkingBeatmap(editorBeatmap.PlayableBeatmap); + + Child = new SetupScreen + { + State = { Value = Visibility.Visible }, + }; + }); } } } From 9aa1564e0de3482c29e9b07927090df4bf0ebd75 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 10:19:04 +0100 Subject: [PATCH 806/961] revert ChannelManager changes --- osu.Game/Online/Chat/ChannelManager.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index f58f1ff40c..bf411d59f6 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -256,21 +256,8 @@ namespace osu.Game.Online.Chat JoinChannel(channel); break; - case "chat": - if (string.IsNullOrWhiteSpace(content)) - { - target.AddNewMessages(new ErrorMessage("Usage: /chat [user]")); - break; - } - - var request = new GetUserRequest(content); - request.Success += OpenPrivateChannel; - request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); - api.Queue(request); - break; - case "help": - target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /chat [user], /np")); + target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /np")); break; default: @@ -614,4 +601,4 @@ namespace osu.Game.Online.Chat : channel.Id == Id; } } -} +} \ No newline at end of file From e409f2dc6d28257b822ffa06230377c80402dae0 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 10:42:38 +0100 Subject: [PATCH 807/961] add xmldoc --- osu.Game/Online/API/Requests/GetUserRequest.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 0c8a4a3578..9470c77b79 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -11,16 +11,30 @@ namespace osu.Game.Online.API.Requests private readonly string userIdentifier; public readonly RulesetInfo Ruleset; + + /// + /// Gets the currently logged-in user. + /// public GetUserRequest() { } + /// + /// Gets a user from their ID. + /// + /// The user to get. + /// The ruleset to get the user's info for. public GetUserRequest(long? userId = null, RulesetInfo ruleset = null) { this.userIdentifier = userId.ToString(); Ruleset = ruleset; } + /// + /// Gets a user from their username. + /// + /// The user to get. + /// The ruleset to get the user's info for. public GetUserRequest(string username = null, RulesetInfo ruleset = null) { this.userIdentifier = username; From e5f886a3158e25181b5c047b9e596f88a72332fb Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 10:45:38 +0100 Subject: [PATCH 808/961] revert unnecessary change --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1e6e1e0ead..a83357f4f5 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -329,7 +329,7 @@ namespace osu.Game break; case LinkAction.OpenUserProfile: - if (int.TryParse(link.Argument, out var userId)) + if (int.TryParse(link.Argument, out int userId)) ShowUser(userId); else ShowUser(link.Argument); From f7369e0d682cc27e0e210e1135b1959abc4e1058 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 14:47:46 +0100 Subject: [PATCH 809/961] create UserIdLookupCache to get user ID when importing scores --- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Scoring/ScoreManager.cs | 35 ++++---- .../Scoring/ScoreManager_UserIdLookupCache.cs | 85 +++++++++++++++++++ 3 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f2d575550a..484cc23161 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -263,7 +263,7 @@ namespace osu.Game dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig, true)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appears where it is necessary diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 3c99dd6637..fcf214268a 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Platform; @@ -27,7 +28,7 @@ using osu.Game.Users; namespace osu.Game.Scoring { - public class ScoreManager : DownloadableArchiveModelManager + public partial class ScoreManager : DownloadableArchiveModelManager { public override IEnumerable HandledExtensions => new[] { ".osr" }; @@ -44,10 +45,13 @@ namespace osu.Game.Scoring [CanBeNull] private readonly OsuConfigManager configManager; + [CanBeNull] + private readonly UserIdLookupCache userIdLookupCache; + private IAPIProvider api { get; set; } public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null, - Func difficulties = null, OsuConfigManager configManager = null) + Func difficulties = null, OsuConfigManager configManager = null, bool performOnlineLookups = false) : base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost) { this.rulesets = rulesets; @@ -55,6 +59,9 @@ namespace osu.Game.Scoring this.difficulties = difficulties; this.configManager = configManager; this.api = api; + + if (performOnlineLookups) + userIdLookupCache = new UserIdLookupCache(api); } protected override ScoreInfo CreateModel(ArchiveReader archive) @@ -76,30 +83,20 @@ namespace osu.Game.Scoring } } - private readonly Dictionary previouslyLookedUpUsernames = new Dictionary(); - - protected override Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) + protected override async Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) { // These scores only provide the user's username but we need the user's ID too. - if (model.UserID <= 1 && model.UserString != null) + if (model.UserID <= 1 && model.UserString != null && userIdLookupCache != null) { - if (previouslyLookedUpUsernames.TryGetValue(model.UserString, out User user)) + try { - model.UserID = user.Id; - return Task.CompletedTask; + model.UserID = await userIdLookupCache.GetUserIdAsync(model.UserString, cancellationToken).ConfigureAwait(false); } - - var request = new GetUserRequest(model.UserString); - request.Success += u => + catch (Exception e) { - model.UserID = u.Id; - previouslyLookedUpUsernames.TryAdd(model.UserString, u); - }; - - api?.Queue(request); + LogForModel(model, $"Online retrieval failed for {model.User} ({e.Message})", e); + } } - - return Task.CompletedTask; } protected override void ExportModelTo(ScoreInfo model, Stream outputStream) diff --git a/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs b/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs new file mode 100644 index 0000000000..dc7e244f14 --- /dev/null +++ b/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs @@ -0,0 +1,85 @@ +// 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.Threading; +using System.Threading.Tasks; +using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Database; + +namespace osu.Game.Scoring +{ + public partial class ScoreManager + { + private class UserIdLookupCache : MemoryCachingComponent + { + private readonly IAPIProvider api; + + public UserIdLookupCache(IAPIProvider api) + { + this.api = api; + } + + /// + /// Perform an API lookup on the specified username, returning the associated ID. + /// + /// The username to lookup. + /// An optional cancellation token. + /// The user ID, or 1 if the user does not exist or the request could not be satisfied. + public Task GetUserIdAsync(string username, CancellationToken token = default) => GetAsync(username, token); + + protected override async Task ComputeValueAsync(string lookup, CancellationToken token = default) + => await queryUserId(lookup).ConfigureAwait(false); + + private readonly Queue<(string username, TaskCompletionSource)> pendingUserTasks = new Queue<(string, TaskCompletionSource)>(); + private Task pendingRequestTask; + private readonly object taskAssignmentLock = new object(); + + private Task queryUserId(string username) + { + lock (taskAssignmentLock) + { + var tcs = new TaskCompletionSource(); + + // Add to the queue. + pendingUserTasks.Enqueue((username, tcs)); + + // Create a request task if there's not already one. + if (pendingRequestTask == null) + createNewTask(); + + return tcs.Task; + } + } + + private void performLookup() + { + (string username, TaskCompletionSource task) next; + + lock (taskAssignmentLock) + { + next = pendingUserTasks.Dequeue(); + } + + var request = new GetUserRequest(next.username); + + // rather than queueing, we maintain our own single-threaded request stream. + // todo: we probably want retry logic here. + api.Perform(request); + + // Create a new request task if there's still more users to query. + lock (taskAssignmentLock) + { + pendingRequestTask = null; + if (pendingUserTasks.Count > 0) + createNewTask(); + } + + next.task.SetResult(request.Result?.Id ?? 1); + } + + private void createNewTask() => pendingRequestTask = Task.Run(performLookup); + } + } +} From 7f9b80e3e5da3c9e362fe028f90d5bfdb5a9e2dc Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 15:11:41 +0100 Subject: [PATCH 810/961] add tests for ShowUser() username overload --- osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs index 03d079261d..70271b0b08 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneUserProfileOverlay.cs @@ -104,6 +104,9 @@ namespace osu.Game.Tests.Visual.Online CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c4.jpg" }, api.IsLoggedIn)); + AddStep("Show ppy from username", () => profile.ShowUser(@"peppy")); + AddStep("Show flyte from username", () => profile.ShowUser(@"flyte")); + AddStep("Hide", profile.Hide); AddStep("Show without reload", profile.Show); } From e78dc1bb4ce6c8d06792bb0c3e2b7042eb33d44f Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 15:27:28 +0100 Subject: [PATCH 811/961] more code quality :/ --- osu.Game/Online/API/Requests/GetUserRequest.cs | 1 - osu.Game/Scoring/ScoreManager.cs | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 9470c77b79..281926c096 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -11,7 +11,6 @@ namespace osu.Game.Online.API.Requests private readonly string userIdentifier; public readonly RulesetInfo Ruleset; - /// /// Gets the currently logged-in user. /// diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index fcf214268a..ccc5579ee5 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Logging; using osu.Framework.Platform; @@ -24,7 +23,6 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring.Legacy; -using osu.Game.Users; namespace osu.Game.Scoring { @@ -48,7 +46,7 @@ namespace osu.Game.Scoring [CanBeNull] private readonly UserIdLookupCache userIdLookupCache; - private IAPIProvider api { get; set; } + private readonly IAPIProvider api; public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null, Func difficulties = null, OsuConfigManager configManager = null, bool performOnlineLookups = false) From b1a995e0bb9d64a663c098518f24790ca0e46a47 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 15:49:48 +0100 Subject: [PATCH 812/961] revert changes --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Scoring/ScoreManager.cs | 30 +------ .../Scoring/ScoreManager_UserIdLookupCache.cs | 85 ------------------- 4 files changed, 6 insertions(+), 113 deletions(-) delete mode 100644 osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index bf411d59f6..1937019ef6 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -601,4 +601,4 @@ namespace osu.Game.Online.Chat : channel.Id == Id; } } -} \ No newline at end of file +} diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 484cc23161..f2d575550a 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -263,7 +263,7 @@ namespace osu.Game dependencies.Cache(fileStore = new FileStore(contextFactory, Storage)); // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() - dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig, true)); + dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => difficultyCache, LocalConfig)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Resources, Host, defaultBeatmap, true)); // this should likely be moved to ArchiveModelManager when another case appears where it is necessary diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index ccc5579ee5..83bcac01ac 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -26,7 +26,7 @@ using osu.Game.Scoring.Legacy; namespace osu.Game.Scoring { - public partial class ScoreManager : DownloadableArchiveModelManager + public class ScoreManager : DownloadableArchiveModelManager { public override IEnumerable HandledExtensions => new[] { ".osr" }; @@ -43,23 +43,14 @@ namespace osu.Game.Scoring [CanBeNull] private readonly OsuConfigManager configManager; - [CanBeNull] - private readonly UserIdLookupCache userIdLookupCache; - - private readonly IAPIProvider api; - public ScoreManager(RulesetStore rulesets, Func beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null, - Func difficulties = null, OsuConfigManager configManager = null, bool performOnlineLookups = false) + Func difficulties = null, OsuConfigManager configManager = null) : base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost) { this.rulesets = rulesets; this.beatmaps = beatmaps; this.difficulties = difficulties; this.configManager = configManager; - this.api = api; - - if (performOnlineLookups) - userIdLookupCache = new UserIdLookupCache(api); } protected override ScoreInfo CreateModel(ArchiveReader archive) @@ -81,21 +72,8 @@ namespace osu.Game.Scoring } } - protected override async Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) - { - // These scores only provide the user's username but we need the user's ID too. - if (model.UserID <= 1 && model.UserString != null && userIdLookupCache != null) - { - try - { - model.UserID = await userIdLookupCache.GetUserIdAsync(model.UserString, cancellationToken).ConfigureAwait(false); - } - catch (Exception e) - { - LogForModel(model, $"Online retrieval failed for {model.User} ({e.Message})", e); - } - } - } + protected override Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default) + => Task.CompletedTask; protected override void ExportModelTo(ScoreInfo model, Stream outputStream) { diff --git a/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs b/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs deleted file mode 100644 index dc7e244f14..0000000000 --- a/osu.Game/Scoring/ScoreManager_UserIdLookupCache.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using osu.Game.Online.API; -using osu.Game.Online.API.Requests; -using osu.Game.Database; - -namespace osu.Game.Scoring -{ - public partial class ScoreManager - { - private class UserIdLookupCache : MemoryCachingComponent - { - private readonly IAPIProvider api; - - public UserIdLookupCache(IAPIProvider api) - { - this.api = api; - } - - /// - /// Perform an API lookup on the specified username, returning the associated ID. - /// - /// The username to lookup. - /// An optional cancellation token. - /// The user ID, or 1 if the user does not exist or the request could not be satisfied. - public Task GetUserIdAsync(string username, CancellationToken token = default) => GetAsync(username, token); - - protected override async Task ComputeValueAsync(string lookup, CancellationToken token = default) - => await queryUserId(lookup).ConfigureAwait(false); - - private readonly Queue<(string username, TaskCompletionSource)> pendingUserTasks = new Queue<(string, TaskCompletionSource)>(); - private Task pendingRequestTask; - private readonly object taskAssignmentLock = new object(); - - private Task queryUserId(string username) - { - lock (taskAssignmentLock) - { - var tcs = new TaskCompletionSource(); - - // Add to the queue. - pendingUserTasks.Enqueue((username, tcs)); - - // Create a request task if there's not already one. - if (pendingRequestTask == null) - createNewTask(); - - return tcs.Task; - } - } - - private void performLookup() - { - (string username, TaskCompletionSource task) next; - - lock (taskAssignmentLock) - { - next = pendingUserTasks.Dequeue(); - } - - var request = new GetUserRequest(next.username); - - // rather than queueing, we maintain our own single-threaded request stream. - // todo: we probably want retry logic here. - api.Perform(request); - - // Create a new request task if there's still more users to query. - lock (taskAssignmentLock) - { - pendingRequestTask = null; - if (pendingUserTasks.Count > 0) - createNewTask(); - } - - next.task.SetResult(request.Result?.Id ?? 1); - } - - private void createNewTask() => pendingRequestTask = Task.Run(performLookup); - } - } -} From 59ca69e41f2e594acc7a398094bb5f99fbd0e27e Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 18:16:57 +0100 Subject: [PATCH 813/961] add /chat command --- osu.Game/Online/Chat/ChannelManager.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 1937019ef6..f58f1ff40c 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -256,8 +256,21 @@ namespace osu.Game.Online.Chat JoinChannel(channel); break; + case "chat": + if (string.IsNullOrWhiteSpace(content)) + { + target.AddNewMessages(new ErrorMessage("Usage: /chat [user]")); + break; + } + + var request = new GetUserRequest(content); + request.Success += OpenPrivateChannel; + request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); + api.Queue(request); + break; + case "help": - target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /np")); + target.AddNewMessages(new InfoMessage("Supported commands: /help, /me [action], /join [channel], /chat [user], /np")); break; default: From e8fb5d2e663be713cfba16e967053952305f6e8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 16:07:24 +0200 Subject: [PATCH 814/961] Add non-functional difficulty switcher to menu --- osu.Game/Screens/Edit/Editor.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 57c78f3c65..a9fcf29c51 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -703,6 +703,13 @@ namespace osu.Game.Screens.Edit if (RuntimeInfo.IsDesktop) fileMenuItems.Add(new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap)); + fileMenuItems.Add(new EditorMenuItemSpacer()); + + var beatmapSet = beatmapManager.QueryBeatmapSet(bs => bs.ID == Beatmap.Value.BeatmapSetInfo.ID) ?? playableBeatmap.BeatmapInfo.BeatmapSet; + var difficultyItems = beatmapSet.Beatmaps.Select(b => new EditorMenuItem(b.Version ?? "(unnamed)")).ToList(); + + fileMenuItems.Add(new EditorMenuItem("Change difficulty") { Items = difficultyItems }); + fileMenuItems.Add(new EditorMenuItemSpacer()); fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit)); return fileMenuItems; From 90f0b6874f4fdda9e3b1dee6d7d2dec883e4cfb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 16:10:49 +0200 Subject: [PATCH 815/961] Highlight current difficulty in switcher --- osu.Game/Screens/Edit/Editor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index a9fcf29c51..cb78a19636 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -706,7 +706,10 @@ namespace osu.Game.Screens.Edit fileMenuItems.Add(new EditorMenuItemSpacer()); var beatmapSet = beatmapManager.QueryBeatmapSet(bs => bs.ID == Beatmap.Value.BeatmapSetInfo.ID) ?? playableBeatmap.BeatmapInfo.BeatmapSet; - var difficultyItems = beatmapSet.Beatmaps.Select(b => new EditorMenuItem(b.Version ?? "(unnamed)")).ToList(); + var difficultyItems = beatmapSet.Beatmaps.Select(b => new ToggleMenuItem(b.Version ?? "(unnamed)") + { + State = { Value = playableBeatmap.BeatmapInfo.Equals(b) } + }).ToList(); fileMenuItems.Add(new EditorMenuItem("Change difficulty") { Items = difficultyItems }); From 7befd030dfe3f8fb58c1886696ce07d737743b73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 16:28:32 +0200 Subject: [PATCH 816/961] Minimal working example of switching difficulties --- osu.Game/Screens/Edit/Editor.cs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index cb78a19636..c7ac232f58 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -35,7 +35,9 @@ using osu.Game.Screens.Edit.Design; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Edit.Timing; using osu.Game.Screens.Edit.Verify; +using osu.Game.Screens.Menu; using osu.Game.Screens.Play; +using osu.Game.Screens.Select; using osu.Game.Users; using osuTK.Graphics; using osuTK.Input; @@ -101,6 +103,9 @@ namespace osu.Game.Screens.Edit [Resolved] private MusicController music { get; set; } + [Resolved(CanBeNull = true)] + private OsuGame game { get; set; } + [BackgroundDependencyLoader] private void load(OsuColour colours, OsuConfigManager config) { @@ -706,10 +711,7 @@ namespace osu.Game.Screens.Edit fileMenuItems.Add(new EditorMenuItemSpacer()); var beatmapSet = beatmapManager.QueryBeatmapSet(bs => bs.ID == Beatmap.Value.BeatmapSetInfo.ID) ?? playableBeatmap.BeatmapInfo.BeatmapSet; - var difficultyItems = beatmapSet.Beatmaps.Select(b => new ToggleMenuItem(b.Version ?? "(unnamed)") - { - State = { Value = playableBeatmap.BeatmapInfo.Equals(b) } - }).ToList(); + var difficultyItems = beatmapSet.Beatmaps.Select(createDifficultyMenuItem).ToList(); fileMenuItems.Add(new EditorMenuItem("Change difficulty") { Items = difficultyItems }); @@ -718,6 +720,28 @@ namespace osu.Game.Screens.Edit return fileMenuItems; } + private ToggleMenuItem createDifficultyMenuItem(BeatmapInfo b) + { + bool isCurrentDifficulty = playableBeatmap.BeatmapInfo.Equals(b); + + var menuItem = new ToggleMenuItem(b.Version ?? "(unnamed)") { State = { Value = isCurrentDifficulty }, }; + + if (!isCurrentDifficulty) + { + menuItem.Action.Value = () => + { + game?.PerformFromScreen(screen => + { + var osuScreen = (OsuScreen)screen; + osuScreen.Beatmap.Value = beatmapManager.GetWorkingBeatmap(b); + screen.Push(new Editor()); + }, new[] { typeof(MainMenu), typeof(SongSelect) }); + }; + } + + return menuItem; + } + public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); public double GetBeatLengthAtTime(double referenceTime) => editorBeatmap.GetBeatLengthAtTime(referenceTime); From fe2520c599b59e5f66e0aefba32c167c98f72052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 16:59:28 +0200 Subject: [PATCH 817/961] Add intermediary screen to avoid going back to menus --- osu.Game/Screens/Edit/Editor.cs | 21 +++++++++++++++------ osu.Game/Screens/Edit/EditorLoader.cs | 27 +++++++++++++++++++++++++++ osu.Game/Screens/Menu/MainMenu.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 2 +- 4 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 osu.Game/Screens/Edit/EditorLoader.cs diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c7ac232f58..bc6d26135b 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using JetBrains.Annotations; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -35,9 +36,7 @@ using osu.Game.Screens.Edit.Design; using osu.Game.Screens.Edit.Setup; using osu.Game.Screens.Edit.Timing; using osu.Game.Screens.Edit.Verify; -using osu.Game.Screens.Menu; using osu.Game.Screens.Play; -using osu.Game.Screens.Select; using osu.Game.Users; using osuTK.Graphics; using osuTK.Input; @@ -77,6 +76,9 @@ namespace osu.Game.Screens.Edit private Container screenContainer; + [CanBeNull] + private readonly EditorLoader loader; + private EditorScreen currentScreen; private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); @@ -106,6 +108,11 @@ namespace osu.Game.Screens.Edit [Resolved(CanBeNull = true)] private OsuGame game { get; set; } + public Editor(EditorLoader loader = null) + { + this.loader = loader; + } + [BackgroundDependencyLoader] private void load(OsuColour colours, OsuConfigManager config) { @@ -730,12 +737,14 @@ namespace osu.Game.Screens.Edit { menuItem.Action.Value = () => { + if (loader != null) + loader.ValidForResume = true; + game?.PerformFromScreen(screen => { - var osuScreen = (OsuScreen)screen; - osuScreen.Beatmap.Value = beatmapManager.GetWorkingBeatmap(b); - screen.Push(new Editor()); - }, new[] { typeof(MainMenu), typeof(SongSelect) }); + if (screen != null && screen == loader) + loader.PushEditor(); + }, new[] { typeof(EditorLoader) }); }; } diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs new file mode 100644 index 0000000000..5c8d0f5b16 --- /dev/null +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -0,0 +1,27 @@ +// 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.Screens; +using osu.Game.Screens.Play; + +namespace osu.Game.Screens.Edit +{ + /// + /// Transition screen for the editor. + /// Used to avoid backing out to main menu/song select when switching difficulties from within the editor. + /// + public class EditorLoader : ScreenWithBeatmapBackground + { + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + PushEditor(); + } + + public void PushEditor() + { + this.Push(new Editor(this)); + ValidForResume = false; + } + } +} diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 1d0182a945..8b2ec43e3e 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Menu OnEdit = delegate { Beatmap.SetDefault(); - this.Push(new Editor()); + this.Push(new EditorLoader()); }, OnSolo = loadSoloSongSelect, OnMultiplayer = () => this.Push(new Multiplayer()), diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index b3d715e580..f11f9fd614 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -349,7 +349,7 @@ namespace osu.Game.Screens.Select throw new InvalidOperationException($"Attempted to edit when {nameof(AllowEditing)} is disabled"); Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap ?? beatmapNoDebounce); - this.Push(new Editor()); + this.Push(new EditorLoader()); } /// From c397cc2027ceb14e216daa075263e2f52588de0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 17:26:09 +0200 Subject: [PATCH 818/961] Restructure proof of concept --- .../Components/Menus/DifficultyMenuItem.cs | 24 +++++++++++++++ osu.Game/Screens/Edit/Editor.cs | 30 ++++++++----------- osu.Game/Screens/Edit/EditorLoader.cs | 11 ++++++- 3 files changed, 47 insertions(+), 18 deletions(-) create mode 100644 osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs diff --git a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs new file mode 100644 index 0000000000..74b18f63ab --- /dev/null +++ b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs @@ -0,0 +1,24 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Graphics.Sprites; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Screens.Edit.Components.Menus +{ + public class DifficultyMenuItem : StatefulMenuItem + { + public DifficultyMenuItem(BeatmapInfo beatmapInfo, bool selected, Action difficultyChangeFunc) + : base(beatmapInfo.Version ?? "(unnamed)", null) + { + State.Value = selected; + + if (!selected) + Action.Value = () => difficultyChangeFunc.Invoke(beatmapInfo); + } + + public override IconUsage? GetIconForState(bool state) => state ? (IconUsage?)FontAwesome.Solid.Check : null; + } +} diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bc6d26135b..f30f92b602 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -727,28 +727,24 @@ namespace osu.Game.Screens.Edit return fileMenuItems; } - private ToggleMenuItem createDifficultyMenuItem(BeatmapInfo b) + private DifficultyMenuItem createDifficultyMenuItem(BeatmapInfo beatmapInfo) { - bool isCurrentDifficulty = playableBeatmap.BeatmapInfo.Equals(b); + bool isCurrentDifficulty = playableBeatmap.BeatmapInfo.Equals(beatmapInfo); + return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, switchToDifficulty); + } - var menuItem = new ToggleMenuItem(b.Version ?? "(unnamed)") { State = { Value = isCurrentDifficulty }, }; + private void switchToDifficulty(BeatmapInfo beatmapInfo) + { + if (loader != null) + loader.ValidForResume = true; - if (!isCurrentDifficulty) + game?.PerformFromScreen(screen => { - menuItem.Action.Value = () => - { - if (loader != null) - loader.ValidForResume = true; + if (screen == null || screen != loader) + return; - game?.PerformFromScreen(screen => - { - if (screen != null && screen == loader) - loader.PushEditor(); - }, new[] { typeof(EditorLoader) }); - }; - } - - return menuItem; + loader.PushEditor(beatmapInfo); + }, new[] { typeof(EditorLoader) }); } public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 5c8d0f5b16..45f2d1bffd 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -1,7 +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 JetBrains.Annotations; +using osu.Framework.Allocation; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit @@ -12,14 +15,20 @@ namespace osu.Game.Screens.Edit /// public class EditorLoader : ScreenWithBeatmapBackground { + [Resolved] + private BeatmapManager beatmapManager { get; set; } + public override void OnEntering(IScreen last) { base.OnEntering(last); PushEditor(); } - public void PushEditor() + public void PushEditor([CanBeNull] BeatmapInfo beatmapInfo = null) { + if (beatmapInfo != null) + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + this.Push(new Editor(this)); ValidForResume = false; } From a9403b65b3eccda6ac7f14826bb90efff5c71555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 17:53:57 +0200 Subject: [PATCH 819/961] Eliminate dependency on OsuGame --- osu.Game/Screens/Edit/Editor.cs | 17 +++++------------ osu.Game/Screens/Edit/EditorLoader.cs | 4 ++-- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index f30f92b602..8e845bac05 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -105,9 +105,6 @@ namespace osu.Game.Screens.Edit [Resolved] private MusicController music { get; set; } - [Resolved(CanBeNull = true)] - private OsuGame game { get; set; } - public Editor(EditorLoader loader = null) { this.loader = loader; @@ -735,16 +732,12 @@ namespace osu.Game.Screens.Edit private void switchToDifficulty(BeatmapInfo beatmapInfo) { - if (loader != null) - loader.ValidForResume = true; + if (loader == null) + return; - game?.PerformFromScreen(screen => - { - if (screen == null || screen != loader) - return; - - loader.PushEditor(beatmapInfo); - }, new[] { typeof(EditorLoader) }); + loader.ValidForResume = true; + this.Exit(); + loader.PushEditor(beatmapInfo); } public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 45f2d1bffd..011f40419c 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -24,13 +24,13 @@ namespace osu.Game.Screens.Edit PushEditor(); } - public void PushEditor([CanBeNull] BeatmapInfo beatmapInfo = null) + public void PushEditor([CanBeNull] BeatmapInfo beatmapInfo = null) => Schedule(() => { if (beatmapInfo != null) Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); this.Push(new Editor(this)); ValidForResume = false; - } + }); } } From c72523bc14afe2b96ad0fb3a298b0edc9d8f5a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 18:32:38 +0200 Subject: [PATCH 820/961] Add basic test for difficulty switching --- .../Editing/TestSceneDifficultySwitching.cs | 91 +++++++++++++++++++ .../Components/Menus/DifficultyMenuItem.cs | 3 + 2 files changed, 94 insertions(+) create mode 100644 osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs new file mode 100644 index 0000000000..4ac2e9cfef --- /dev/null +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Testing; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; +using osu.Game.Screens.Edit; +using osu.Game.Screens.Edit.Components.Menus; +using osu.Game.Tests.Beatmaps.IO; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.Editing +{ + public class TestSceneDifficultySwitching : ScreenTestScene + { + private BeatmapSetInfo importedBeatmapSet; + + [Resolved] + private OsuGameBase game { get; set; } + + private Editor editor; + + [Resolved] + private BeatmapManager beatmaps { get; set; } + + [SetUpSteps] + public void SetUp() + { + AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result); + + AddStep("set current beatmap", () => Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First())); + AddStep("push loader", () => Stack.Push(new EditorLoader())); + + AddUntilStep("wait for editor to load", () => Stack.CurrentScreen is Editor); + AddStep("store editor", () => editor = (Editor)Stack.CurrentScreen); + } + + [Test] + public void TestBasicSwitch() + { + BeatmapInfo targetDifficulty = null; + + AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo))); + switchToDifficulty(() => targetDifficulty); + confirmEditingBeatmap(() => targetDifficulty); + + AddStep("exit editor", () => Stack.Exit()); + // ensure editor loader didn't resume. + AddAssert("stack empty", () => Stack.CurrentScreen == null); + } + + private void switchToDifficulty(Func difficulty) + { + AddUntilStep("wait for menubar to load", () => editor.ChildrenOfType().Any()); + AddStep("open file menu", () => + { + var menuBar = editor.ChildrenOfType().Single(); + var fileMenu = menuBar.ChildrenOfType().First(); + InputManager.MoveMouseTo(fileMenu); + InputManager.Click(MouseButton.Left); + }); + + AddStep("open difficulty menu", () => + { + var difficultySelector = + editor.ChildrenOfType().Single(item => item.Item.Text.Value.ToString().Contains("Change difficulty")); + InputManager.MoveMouseTo(difficultySelector); + }); + AddWaitStep("wait for open", 3); + + AddStep("switch to target difficulty", () => + { + var difficultyMenuItem = + editor.ChildrenOfType() + .Last(item => item.Item is DifficultyMenuItem difficultyItem && difficultyItem.Beatmap.Equals(difficulty.Invoke())); + InputManager.MoveMouseTo(difficultyMenuItem); + InputManager.Click(MouseButton.Left); + }); + } + + private void confirmEditingBeatmap(Func targetDifficulty) + { + AddUntilStep("current beatmap is correct", () => Beatmap.Value.BeatmapInfo.Equals(targetDifficulty.Invoke())); + AddUntilStep("current screen is editor", () => Stack.CurrentScreen is Editor); + } + } +} diff --git a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs index 74b18f63ab..5f9b72447b 100644 --- a/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/DifficultyMenuItem.cs @@ -10,9 +10,12 @@ namespace osu.Game.Screens.Edit.Components.Menus { public class DifficultyMenuItem : StatefulMenuItem { + public BeatmapInfo Beatmap { get; } + public DifficultyMenuItem(BeatmapInfo beatmapInfo, bool selected, Action difficultyChangeFunc) : base(beatmapInfo.Version ?? "(unnamed)", null) { + Beatmap = beatmapInfo; State.Value = selected; if (!selected) From 382269b362061da851565b88092c08b923eeadbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 19:11:46 +0200 Subject: [PATCH 821/961] Test staying on same difficulty due to unsaved changes --- .../Editing/TestSceneDifficultySwitching.cs | 37 ++++++++++++++++++- osu.Game/Screens/Edit/Editor.cs | 13 ++++++- osu.Game/Screens/Edit/EditorLoader.cs | 25 ++++++++++--- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 3 +- 4 files changed, 68 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index 4ac2e9cfef..60c2518a7e 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays.Dialog; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Tests.Beatmaps.IO; @@ -35,8 +36,9 @@ namespace osu.Game.Tests.Visual.Editing AddStep("set current beatmap", () => Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First())); AddStep("push loader", () => Stack.Push(new EditorLoader())); - AddUntilStep("wait for editor to load", () => Stack.CurrentScreen is Editor); + AddUntilStep("wait for editor push", () => Stack.CurrentScreen is Editor); AddStep("store editor", () => editor = (Editor)Stack.CurrentScreen); + AddUntilStep("wait for editor to load", () => editor.IsLoaded); } [Test] @@ -53,6 +55,39 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("stack empty", () => Stack.CurrentScreen == null); } + [Test] + public void TestPreventSwitchDueToUnsavedChanges() + { + BeatmapInfo targetDifficulty = null; + PromptForSaveDialog saveDialog = null; + + AddStep("remove first hitobject", () => + { + var editorBeatmap = editor.ChildrenOfType().Single(); + editorBeatmap.RemoveAt(0); + }); + + AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo))); + switchToDifficulty(() => targetDifficulty); + + AddUntilStep("prompt for save dialog shown", () => + { + saveDialog = this.ChildrenOfType().Single(); + return saveDialog != null; + }); + AddStep("continue editing", () => + { + var continueButton = saveDialog.ChildrenOfType().Last(); + continueButton.TriggerClick(); + }); + + confirmEditingBeatmap(() => importedBeatmapSet.Beatmaps.First()); + + AddRepeatStep("exit editor forcefully", () => Stack.Exit(), 2); + // ensure editor loader didn't resume. + AddAssert("stack empty", () => Stack.CurrentScreen == null); + } + private void switchToDifficulty(Func difficulty) { AddUntilStep("wait for menubar to load", () => editor.ChildrenOfType().Any()); diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 8e845bac05..df08e0a017 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -498,7 +498,7 @@ namespace osu.Game.Screens.Edit if (isNewBeatmap || HasUnsavedChanges) { - dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave)); + dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave, cancelPendingDifficultySwitch)); return true; } } @@ -737,7 +737,16 @@ namespace osu.Game.Screens.Edit loader.ValidForResume = true; this.Exit(); - loader.PushEditor(beatmapInfo); + loader.ScheduleDifficultySwitch(beatmapInfo); + } + + private void cancelPendingDifficultySwitch() + { + if (loader == null) + return; + + loader.ValidForResume = false; + loader.CancelDifficultySwitch(); } public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 011f40419c..d913076e83 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Screens; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Screens.Play; @@ -18,19 +19,31 @@ namespace osu.Game.Screens.Edit [Resolved] private BeatmapManager beatmapManager { get; set; } + [CanBeNull] + private ScheduledDelegate scheduledDifficultySwitch; + public override void OnEntering(IScreen last) { base.OnEntering(last); - PushEditor(); + pushEditor(); } - public void PushEditor([CanBeNull] BeatmapInfo beatmapInfo = null) => Schedule(() => + private void pushEditor() { - if (beatmapInfo != null) - Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); - this.Push(new Editor(this)); ValidForResume = false; - }); + } + + public void ScheduleDifficultySwitch(BeatmapInfo beatmapInfo) + { + CancelDifficultySwitch(); + scheduledDifficultySwitch = Schedule(() => + { + Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + pushEditor(); + }); + } + + public void CancelDifficultySwitch() => scheduledDifficultySwitch?.Cancel(); } } diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index 16504b47bd..e308a9533d 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -9,7 +9,7 @@ namespace osu.Game.Screens.Edit { public class PromptForSaveDialog : PopupDialog { - public PromptForSaveDialog(Action exit, Action saveAndExit) + public PromptForSaveDialog(Action exit, Action saveAndExit, Action cancel) { HeaderText = "Did you want to save your changes?"; @@ -30,6 +30,7 @@ namespace osu.Game.Screens.Edit new PopupDialogCancelButton { Text = @"Oops, continue editing", + Action = cancel }, }; } From 74a129dc27fd3c0bc6ce6e5919106f7a1b9e45ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 19:20:18 +0200 Subject: [PATCH 822/961] Test switching difficulties after discarding changes --- .../Editing/TestSceneDifficultySwitching.cs | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index 60c2518a7e..ecf1fec850 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -88,6 +88,39 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("stack empty", () => Stack.CurrentScreen == null); } + [Test] + public void TestAllowSwitchAfterDiscardingUnsavedChanges() + { + BeatmapInfo targetDifficulty = null; + PromptForSaveDialog saveDialog = null; + + AddStep("remove first hitobject", () => + { + var editorBeatmap = editor.ChildrenOfType().Single(); + editorBeatmap.RemoveAt(0); + }); + + AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo))); + switchToDifficulty(() => targetDifficulty); + + AddUntilStep("prompt for save dialog shown", () => + { + saveDialog = this.ChildrenOfType().Single(); + return saveDialog != null; + }); + AddStep("discard changes", () => + { + var continueButton = saveDialog.ChildrenOfType().Single(); + continueButton.TriggerClick(); + }); + + confirmEditingBeatmap(() => targetDifficulty); + + AddStep("exit editor forcefully", () => Stack.Exit()); + // ensure editor loader didn't resume. + AddAssert("stack empty", () => Stack.CurrentScreen == null); + } + private void switchToDifficulty(Func difficulty) { AddUntilStep("wait for menubar to load", () => editor.ChildrenOfType().Any()); From 7012a1d9340a01011cbc0e3ef190f3f0ec8030d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 20:24:07 +0200 Subject: [PATCH 823/961] Fix issues with main menu -> editor loader transition --- .../Editing/TestSceneDifficultySwitching.cs | 15 +++++++++++-- osu.Game/Screens/Edit/EditorLoader.cs | 22 ++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index ecf1fec850..0f3d413a7d 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -11,6 +11,7 @@ using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Dialog; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Menus; +using osu.Game.Screens.Menu; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; @@ -19,15 +20,25 @@ namespace osu.Game.Tests.Visual.Editing public class TestSceneDifficultySwitching : ScreenTestScene { private BeatmapSetInfo importedBeatmapSet; + private Editor editor; + + // required for screen transitions to work properly + // (see comment in EditorLoader.LogoArriving). + [Cached] + private OsuLogo logo = new OsuLogo + { + Alpha = 0 + }; [Resolved] private OsuGameBase game { get; set; } - private Editor editor; - [Resolved] private BeatmapManager beatmaps { get; set; } + [BackgroundDependencyLoader] + private void load() => Add(logo); + [SetUpSteps] public void SetUp() { diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index d913076e83..07eb5e5b1b 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -3,10 +3,11 @@ using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; -using osu.Game.Screens.Play; +using osu.Game.Screens.Menu; namespace osu.Game.Screens.Edit { @@ -14,18 +15,29 @@ namespace osu.Game.Screens.Edit /// Transition screen for the editor. /// Used to avoid backing out to main menu/song select when switching difficulties from within the editor. /// - public class EditorLoader : ScreenWithBeatmapBackground + public class EditorLoader : OsuScreen { + public override float BackgroundParallaxAmount => 0.1f; + + public override bool AllowBackButton => false; + + public override bool HideOverlaysOnEnter => true; + + public override bool DisallowExternalBeatmapRulesetChanges => true; + [Resolved] private BeatmapManager beatmapManager { get; set; } [CanBeNull] private ScheduledDelegate scheduledDifficultySwitch; - public override void OnEntering(IScreen last) + protected override void LogoArriving(OsuLogo logo, bool resuming) { - base.OnEntering(last); - pushEditor(); + base.LogoArriving(logo, resuming); + // the push cannot happen in OnEntering() or similar (even if scheduled), because the transition from main menu will look bad. + // that is because this screen pushing the editor makes it no longer current, and OsuScreen checks if the screen is current + // before enqueueing this screen's LogoArriving onto the logo animation sequence. + logo.Delay(300).Schedule(pushEditor); } private void pushEditor() From d6a47fd99ceeb2f4a707da8c11ed66c940fc787e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 5 Sep 2021 21:00:19 +0200 Subject: [PATCH 824/961] Sort difficulties by ruleset and star rating in menu --- osu.Game/Screens/Edit/Editor.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index df08e0a017..7d0b936df9 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -715,7 +715,17 @@ namespace osu.Game.Screens.Edit fileMenuItems.Add(new EditorMenuItemSpacer()); var beatmapSet = beatmapManager.QueryBeatmapSet(bs => bs.ID == Beatmap.Value.BeatmapSetInfo.ID) ?? playableBeatmap.BeatmapInfo.BeatmapSet; - var difficultyItems = beatmapSet.Beatmaps.Select(createDifficultyMenuItem).ToList(); + + var difficultyItems = new List(); + + foreach (var rulesetBeatmaps in beatmapSet.Beatmaps.GroupBy(b => b.RulesetID).OrderBy(group => group.Key)) + { + if (difficultyItems.Count > 0) + difficultyItems.Add(new EditorMenuItemSpacer()); + + foreach (var beatmap in rulesetBeatmaps.OrderBy(b => b.StarDifficulty)) + difficultyItems.Add(createDifficultyMenuItem(beatmap)); + } fileMenuItems.Add(new EditorMenuItem("Change difficulty") { Items = difficultyItems }); From cb6cee9aea75901d4bcf230e5b1cf8d8f5c13c1a Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 21:10:08 +0100 Subject: [PATCH 825/961] add /query as alias of /chat --- osu.Game/Online/Chat/ChannelManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index f58f1ff40c..d72a050d84 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -257,6 +257,7 @@ namespace osu.Game.Online.Chat break; case "chat": + case "query": if (string.IsNullOrWhiteSpace(content)) { target.AddNewMessages(new ErrorMessage("Usage: /chat [user]")); From 5c385e84ea4988528ff628867c34705d22c889c3 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sun, 5 Sep 2021 21:20:19 +0100 Subject: [PATCH 826/961] wrong command name in query message --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index d72a050d84..d2500f0d7f 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -260,7 +260,7 @@ namespace osu.Game.Online.Chat case "query": if (string.IsNullOrWhiteSpace(content)) { - target.AddNewMessages(new ErrorMessage("Usage: /chat [user]")); + target.AddNewMessages(new ErrorMessage($"Usage: /{command} [user]")); break; } From 458cde832da5a75b742fb808637e559de62fad3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Sep 2021 14:09:40 +0900 Subject: [PATCH 827/961] Avoid using SSDQ for validity computation --- .../Settings/TestSceneTabletSettings.cs | 14 +----- .../Sections/Input/TabletAreaSelection.cs | 44 ++++++++++++------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 49d6b7033e..2486abdd7a 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs @@ -1,11 +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.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Testing; using osu.Framework.Utils; @@ -93,17 +91,9 @@ namespace osu.Game.Tests.Visual.Settings ensureValid(); } - private void ensureValid() - { - AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType().All(c => !c.Transforms.Any())); - AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); - } + private void ensureValid() => AddAssert("area valid", () => settings.AreaSelection.IsWithinBounds); - private void ensureInvalid() - { - AddUntilStep("wait for transforms", () => settings.AreaSelection.ChildrenOfType().All(c => !c.Transforms.Any())); - AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds); - } + private void ensureInvalid() => AddAssert("area invalid", () => !settings.AreaSelection.IsWithinBounds); public class TestTabletHandler : ITabletHandler { diff --git a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs index d12052b24d..58abfab29c 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs @@ -114,29 +114,30 @@ namespace osu.Game.Overlays.Settings.Sections.Input areaOffset.BindTo(handler.AreaOffset); areaOffset.BindValueChanged(val => { - usableAreaContainer.MoveTo(val.NewValue, 100, Easing.OutQuint) - .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + usableAreaContainer.MoveTo(val.NewValue, 100, Easing.OutQuint); + checkBounds(); }, true); areaSize.BindTo(handler.AreaSize); areaSize.BindValueChanged(val => { - usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint) - .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint); int x = (int)val.NewValue.X; int y = (int)val.NewValue.Y; int commonDivider = greatestCommonDivider(x, y); usableAreaText.Text = $"{(float)x / commonDivider}:{(float)y / commonDivider}"; + checkBounds(); }, true); rotation.BindTo(handler.Rotation); rotation.BindValueChanged(val => { - usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint) - .OnComplete(_ => checkBounds()); // required as we are using SSDQ. + usableAreaContainer.RotateTo(val.NewValue, 100, Easing.OutQuint); tabletContainer.RotateTo(-val.NewValue, 800, Easing.OutQuint); + + checkBounds(); }, true); tablet.BindTo(handler.Tablet); @@ -174,22 +175,33 @@ namespace osu.Game.Overlays.Settings.Sections.Input if (tablet.Value == null) return; - // All of this manual logic is just to get around floating point issues when doing a contains check on the screen quads. - // This is best effort, as it's only used for display purposes. If we need for anything more, manual math on the raw values should be preferred. - var containerQuad = tabletContainer.ScreenSpaceDrawQuad.AABBFloat.Inflate(1); - var usableAreaQuad = Quad.FromRectangle(usableAreaContainer.ScreenSpaceDrawQuad.AABBFloat); + // allow for some degree of floating point error, as we don't care about being perfect here. + const float lenience = 0.5f; + + var tabletArea = new Quad(-lenience, -lenience, tablet.Value.Size.X + lenience * 2, tablet.Value.Size.Y + lenience * 2); + + var halfUsableArea = areaSize.Value / 2; + var offset = areaOffset.Value; + + var usableAreaQuad = new Quad( + new Vector2(-halfUsableArea.X, -halfUsableArea.Y), + new Vector2(halfUsableArea.X, -halfUsableArea.Y), + new Vector2(-halfUsableArea.X, halfUsableArea.Y), + new Vector2(halfUsableArea.X, halfUsableArea.Y) + ); var matrix = Matrix3.Identity; - MatrixExtensions.TranslateFromLeft(ref matrix, usableAreaQuad.Centre); + + MatrixExtensions.TranslateFromLeft(ref matrix, offset); MatrixExtensions.RotateFromLeft(ref matrix, MathUtils.DegreesToRadians(rotation.Value)); - MatrixExtensions.TranslateFromLeft(ref matrix, -usableAreaQuad.Centre); + usableAreaQuad *= matrix; IsWithinBounds = - containerQuad.Contains(usableAreaQuad.TopLeft) && - containerQuad.Contains(usableAreaQuad.TopRight) && - containerQuad.Contains(usableAreaQuad.BottomLeft) && - containerQuad.Contains(usableAreaQuad.BottomRight); + tabletArea.Contains(usableAreaQuad.TopLeft) && + tabletArea.Contains(usableAreaQuad.TopRight) && + tabletArea.Contains(usableAreaQuad.BottomLeft) && + tabletArea.Contains(usableAreaQuad.BottomRight); usableFill.FadeColour(IsWithinBounds ? colour.Blue : colour.RedLight, 100); } From 6f482c3602b3fd2c6801878e0fcb368ba5dd1633 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Sep 2021 14:14:42 +0900 Subject: [PATCH 828/961] Add test coverage of sharper aspect ratio --- .../Settings/TestSceneTabletSettings.cs | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs index 2486abdd7a..997eac709d 100644 --- a/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs +++ b/osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.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 NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -8,6 +9,7 @@ using osu.Framework.Input.Handlers.Tablet; using osu.Framework.Testing; using osu.Framework.Utils; using osu.Game.Overlays; +using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings.Sections.Input; using osuTK; @@ -51,6 +53,27 @@ namespace osu.Game.Tests.Visual.Settings AddStep("Test no tablet present", () => tabletHandler.SetTabletSize(Vector2.Zero)); } + [Test] + public void TestWideAspectRatioValidity() + { + AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100))); + + AddStep("Reset to full area", () => settings.ChildrenOfType().First().TriggerClick()); + ensureValid(); + + AddStep("rotate 10", () => tabletHandler.Rotation.Value = 10); + ensureInvalid(); + + AddStep("scale down", () => tabletHandler.AreaSize.Value *= 0.9f); + ensureInvalid(); + + AddStep("scale down", () => tabletHandler.AreaSize.Value *= 0.9f); + ensureInvalid(); + + AddStep("scale down", () => tabletHandler.AreaSize.Value *= 0.9f); + ensureValid(); + } + [Test] public void TestRotationValidity() { From 1c4a3c584a76fb9ecbf7b56d6d62850fcc89b88d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 6 Sep 2021 15:04:27 +0900 Subject: [PATCH 829/961] Use correct lookup type to ensure username based lookups always prefer username --- osu.Game/Online/API/Requests/GetUserRequest.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index 281926c096..e49c4ab298 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -8,8 +8,9 @@ namespace osu.Game.Online.API.Requests { public class GetUserRequest : APIRequest { - private readonly string userIdentifier; + private readonly string lookup; public readonly RulesetInfo Ruleset; + private readonly LookupType lookupType; /// /// Gets the currently logged-in user. @@ -25,7 +26,8 @@ namespace osu.Game.Online.API.Requests /// The ruleset to get the user's info for. public GetUserRequest(long? userId = null, RulesetInfo ruleset = null) { - this.userIdentifier = userId.ToString(); + lookup = userId.ToString(); + lookupType = LookupType.Id; Ruleset = ruleset; } @@ -36,10 +38,17 @@ namespace osu.Game.Online.API.Requests /// The ruleset to get the user's info for. public GetUserRequest(string username = null, RulesetInfo ruleset = null) { - this.userIdentifier = username; + lookup = username; + lookupType = LookupType.Username; Ruleset = ruleset; } - protected override string Target => userIdentifier != null ? $@"users/{userIdentifier}/{Ruleset?.ShortName}" : $@"me/{Ruleset?.ShortName}"; + protected override string Target => lookup != null ? $@"users/{lookup}/{Ruleset?.ShortName}?k={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; + + private enum LookupType + { + Id, + Username + } } } From 62d65f81fb785ae4656b312f6617f469401349d6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 6 Sep 2021 16:53:09 +0900 Subject: [PATCH 830/961] Limit at 10000 entries --- .github/workflows/test-diffcalc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 3bec11928f..d963e49d9f 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -156,6 +156,7 @@ jobs: AND m.mods = p.mods WHERE abs(m.diff_unified - p.diff_unified) > 0.1 ORDER BY abs(m.diff_unified - p.diff_unified) - DESC;" + DESC + LIMIT 10000;" # Todo: Run ppcalc \ No newline at end of file From 401d38fc051366cb26f3f25bf389decbf5a5bfec Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 6 Sep 2021 19:07:28 +0900 Subject: [PATCH 831/961] Fix possible nullref --- osu.Game/Screens/Ranking/ScorePanelList.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 711e0d60ec..4ac30ef4ed 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -301,6 +301,9 @@ namespace osu.Game.Screens.Ranking protected override bool OnKeyDown(KeyDownEvent e) { + if (expandedPanel == null) + return base.OnKeyDown(e); + var expandedPanelIndex = flow.GetPanelIndex(expandedPanel.Score); switch (e.Key) From 20100b8894d5a58af13e1351628e0366e6256ac5 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 6 Sep 2021 20:20:52 +0900 Subject: [PATCH 832/961] Fix a few test failures --- .../Visual/Playlists/TestScenePlaylistsResultsScreen.cs | 2 ++ osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs | 8 +++++--- osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs | 5 +++++ .../Visual/UserInterface/TestSceneDeleteLocalScore.cs | 4 ++-- osu.Game/Screens/Ranking/ScorePanelList.cs | 2 ++ 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index 61d49e4018..b826683cd5 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -160,6 +160,8 @@ namespace osu.Game.Tests.Visual.Playlists Ruleset = { Value = new OsuRuleset().RulesetInfo } })); }); + + AddUntilStep("wait for load", () => resultsScreen.ChildrenOfType().FirstOrDefault()?.AllPanelsVisible == true); } private void waitForDisplay() diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs index ba6b6bd529..34a9610804 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs @@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.Ranking TestResultsScreen screen = null; AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen())); - AddUntilStep("wait for loaded", () => screen.IsLoaded); + AddUntilStep("wait for load", () => this.ChildrenOfType().Single().AllPanelsVisible); AddStep("click expanded panel", () => { @@ -138,7 +138,7 @@ namespace osu.Game.Tests.Visual.Ranking TestResultsScreen screen = null; AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen())); - AddUntilStep("wait for loaded", () => screen.IsLoaded); + AddUntilStep("wait for load", () => this.ChildrenOfType().Single().AllPanelsVisible); AddStep("click expanded panel", () => { @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Ranking TestResultsScreen screen = null; AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen())); - AddUntilStep("wait for loaded", () => screen.IsLoaded); + AddUntilStep("wait for load", () => this.ChildrenOfType().Single().AllPanelsVisible); ScorePanel expandedPanel = null; ScorePanel contractedPanel = null; @@ -201,6 +201,7 @@ namespace osu.Game.Tests.Visual.Ranking [Test] public void TestFetchScoresAfterShowingStatistics() + { DelayedFetchResultsScreen screen = null; @@ -223,6 +224,7 @@ namespace osu.Game.Tests.Visual.Ranking TestResultsScreen screen = null; AddStep("load results", () => Child = new TestResultsContainer(screen = createResultsScreen())); + AddUntilStep("wait for load", () => this.ChildrenOfType().Single().AllPanelsVisible); AddAssert("download button is disabled", () => !screen.ChildrenOfType().Last().Enabled.Value); diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs index f330e99d55..b2585c0509 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs @@ -159,6 +159,9 @@ namespace osu.Game.Tests.Visual.Ranking var firstScore = new TestScoreInfo(new OsuRuleset().RulesetInfo); var secondScore = new TestScoreInfo(new OsuRuleset().RulesetInfo); + firstScore.User.Username = "A"; + secondScore.User.Username = "B"; + createListStep(() => new ScorePanelList()); AddStep("add scores and select first", () => @@ -168,6 +171,8 @@ namespace osu.Game.Tests.Visual.Ranking list.SelectedScore.Value = firstScore; }); + AddUntilStep("wait for load", () => list.AllPanelsVisible); + assertScoreState(firstScore, true); assertScoreState(secondScore, false); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 98482601ee..8efee2723f 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -158,14 +158,14 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.Click(MouseButton.Left); }); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scores[0].OnlineScoreID)); + AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s != scores[0])); } [Test] public void TestDeleteViaDatabase() { AddStep("delete top score", () => scoreManager.Delete(scores[0])); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scores[0].OnlineScoreID)); + AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s != scores[0])); } } } diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 4ac30ef4ed..6d65137984 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -47,6 +47,8 @@ namespace osu.Game.Screens.Ranking /// public bool IsScrolledToEnd => flow.Count > 0 && scroll.ScrollableExtent > 0 && scroll.IsScrolledToEnd(scroll_endpoint_distance); + public bool AllPanelsVisible => flow.All(p => p.IsPresent); + /// /// The current scroll position. /// From 2a5b857f10f51f0d5e2cd3666be3e08db9ed8338 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 00:45:53 +0900 Subject: [PATCH 833/961] Avoid loading unnecessary fonts in headless testing --- osu.Game/OsuGameBase.cs | 55 +++++++++++++++------------ osu.Game/Tests/Visual/OsuTestScene.cs | 5 +++ 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 762216e93c..a63e59f3d3 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -205,31 +205,7 @@ namespace osu.Game dependencies.CacheAs(this); dependencies.CacheAs(LocalConfig); - AddFont(Resources, @"Fonts/osuFont"); - - AddFont(Resources, @"Fonts/Torus/Torus-Regular"); - AddFont(Resources, @"Fonts/Torus/Torus-Light"); - AddFont(Resources, @"Fonts/Torus/Torus-SemiBold"); - AddFont(Resources, @"Fonts/Torus/Torus-Bold"); - - AddFont(Resources, @"Fonts/Inter/Inter-Regular"); - AddFont(Resources, @"Fonts/Inter/Inter-RegularItalic"); - AddFont(Resources, @"Fonts/Inter/Inter-Light"); - AddFont(Resources, @"Fonts/Inter/Inter-LightItalic"); - AddFont(Resources, @"Fonts/Inter/Inter-SemiBold"); - AddFont(Resources, @"Fonts/Inter/Inter-SemiBoldItalic"); - AddFont(Resources, @"Fonts/Inter/Inter-Bold"); - AddFont(Resources, @"Fonts/Inter/Inter-BoldItalic"); - - AddFont(Resources, @"Fonts/Noto/Noto-Basic"); - AddFont(Resources, @"Fonts/Noto/Noto-Hangul"); - AddFont(Resources, @"Fonts/Noto/Noto-CJK-Basic"); - AddFont(Resources, @"Fonts/Noto/Noto-CJK-Compatibility"); - AddFont(Resources, @"Fonts/Noto/Noto-Thai"); - - AddFont(Resources, @"Fonts/Venera/Venera-Light"); - AddFont(Resources, @"Fonts/Venera/Venera-Bold"); - AddFont(Resources, @"Fonts/Venera/Venera-Black"); + InitialiseFonts(); Audio.Samples.PlaybackConcurrency = SAMPLE_CONCURRENCY; @@ -368,6 +344,35 @@ namespace osu.Game Ruleset.BindValueChanged(onRulesetChanged); } + protected virtual void InitialiseFonts() + { + AddFont(Resources, @"Fonts/osuFont"); + + AddFont(Resources, @"Fonts/Torus/Torus-Regular"); + AddFont(Resources, @"Fonts/Torus/Torus-Light"); + AddFont(Resources, @"Fonts/Torus/Torus-SemiBold"); + AddFont(Resources, @"Fonts/Torus/Torus-Bold"); + + AddFont(Resources, @"Fonts/Inter/Inter-Regular"); + AddFont(Resources, @"Fonts/Inter/Inter-RegularItalic"); + AddFont(Resources, @"Fonts/Inter/Inter-Light"); + AddFont(Resources, @"Fonts/Inter/Inter-LightItalic"); + AddFont(Resources, @"Fonts/Inter/Inter-SemiBold"); + AddFont(Resources, @"Fonts/Inter/Inter-SemiBoldItalic"); + AddFont(Resources, @"Fonts/Inter/Inter-Bold"); + AddFont(Resources, @"Fonts/Inter/Inter-BoldItalic"); + + AddFont(Resources, @"Fonts/Noto/Noto-Basic"); + AddFont(Resources, @"Fonts/Noto/Noto-Hangul"); + AddFont(Resources, @"Fonts/Noto/Noto-CJK-Basic"); + AddFont(Resources, @"Fonts/Noto/Noto-CJK-Compatibility"); + AddFont(Resources, @"Fonts/Noto/Noto-Thai"); + + AddFont(Resources, @"Fonts/Venera/Venera-Light"); + AddFont(Resources, @"Fonts/Venera/Venera-Bold"); + AddFont(Resources, @"Fonts/Venera/Venera-Black"); + } + private IDisposable blocking; private void updateThreadStateChanged(ValueChangedEvent state) diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index ef9181c8a6..03434961ea 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -367,6 +367,11 @@ namespace osu.Game.Tests.Visual Add(runner = new TestSceneTestRunner.TestRunner()); } + protected override void InitialiseFonts() + { + // skip fonts load as it's not required for testing purposes. + } + public void RunTestBlocking(TestScene test) => runner.RunTestBlocking(test); } } From bd7d6dd35d54ca11c11616ea1b5f97a74e87b2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 6 Sep 2021 21:27:17 +0200 Subject: [PATCH 834/961] Rename method --- osu.Game/Screens/Edit/Editor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 7d0b936df9..d0b50c13e6 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -498,7 +498,7 @@ namespace osu.Game.Screens.Edit if (isNewBeatmap || HasUnsavedChanges) { - dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave, cancelPendingDifficultySwitch)); + dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave, cancelExit)); return true; } } @@ -750,7 +750,7 @@ namespace osu.Game.Screens.Edit loader.ScheduleDifficultySwitch(beatmapInfo); } - private void cancelPendingDifficultySwitch() + private void cancelExit() { if (loader == null) return; From 2d59008f528f441cff81e9144b25bf208da04173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 6 Sep 2021 21:30:50 +0200 Subject: [PATCH 835/961] Move screen management logic to `EditorLoader` --- osu.Game/Screens/Edit/Editor.cs | 19 ++----------------- osu.Game/Screens/Edit/EditorLoader.cs | 11 +++++++++-- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index d0b50c13e6..1b9a94da58 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -740,24 +740,9 @@ namespace osu.Game.Screens.Edit return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, switchToDifficulty); } - private void switchToDifficulty(BeatmapInfo beatmapInfo) - { - if (loader == null) - return; + private void switchToDifficulty(BeatmapInfo beatmapInfo) => loader?.ScheduleDifficultySwitch(beatmapInfo); - loader.ValidForResume = true; - this.Exit(); - loader.ScheduleDifficultySwitch(beatmapInfo); - } - - private void cancelExit() - { - if (loader == null) - return; - - loader.ValidForResume = false; - loader.CancelDifficultySwitch(); - } + private void cancelExit() => loader?.CancelPendingDifficultySwitch(); public double SnapTime(double time, double? referenceTime) => editorBeatmap.SnapTime(time, referenceTime); diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 07eb5e5b1b..fbb358d217 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -48,7 +48,10 @@ namespace osu.Game.Screens.Edit public void ScheduleDifficultySwitch(BeatmapInfo beatmapInfo) { - CancelDifficultySwitch(); + scheduledDifficultySwitch?.Cancel(); + ValidForResume = true; + + this.MakeCurrent(); scheduledDifficultySwitch = Schedule(() => { Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); @@ -56,6 +59,10 @@ namespace osu.Game.Screens.Edit }); } - public void CancelDifficultySwitch() => scheduledDifficultySwitch?.Cancel(); + public void CancelPendingDifficultySwitch() + { + scheduledDifficultySwitch?.Cancel(); + ValidForResume = false; + } } } From 5b9f37702b72e69e1976e6091bb8754650149135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 6 Sep 2021 21:31:59 +0200 Subject: [PATCH 836/961] Remove unnecessary delay before pushing editor from loader --- osu.Game/Screens/Edit/EditorLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index fbb358d217..92420fa7c0 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -3,7 +3,6 @@ using JetBrains.Annotations; using osu.Framework.Allocation; -using osu.Framework.Graphics; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; @@ -34,10 +33,11 @@ namespace osu.Game.Screens.Edit protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); + // the push cannot happen in OnEntering() or similar (even if scheduled), because the transition from main menu will look bad. // that is because this screen pushing the editor makes it no longer current, and OsuScreen checks if the screen is current // before enqueueing this screen's LogoArriving onto the logo animation sequence. - logo.Delay(300).Schedule(pushEditor); + pushEditor(); } private void pushEditor() From c9325cc41947c5c1b62afe5b3bc249b643f5527b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 7 Sep 2021 14:15:23 +0900 Subject: [PATCH 837/961] Fix results screen test scene --- .../Visual/Playlists/TestScenePlaylistsResultsScreen.cs | 1 + osu.Game/Screens/Ranking/ScorePanelList.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs index b826683cd5..4bcc887b9f 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs @@ -167,6 +167,7 @@ namespace osu.Game.Tests.Visual.Playlists private void waitForDisplay() { AddUntilStep("wait for request to complete", () => requestComplete); + AddUntilStep("wait for panels to be visible", () => resultsScreen.ChildrenOfType().FirstOrDefault()?.AllPanelsVisible == true); AddWaitStep("wait for display", 5); } diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index 6d65137984..a847df344f 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -40,12 +40,12 @@ namespace osu.Game.Screens.Ranking /// /// Whether this can be scrolled and is currently scrolled to the start. /// - public bool IsScrolledToStart => flow.Count > 0 && scroll.ScrollableExtent > 0 && scroll.Current <= scroll_endpoint_distance; + public bool IsScrolledToStart => flow.Count > 0 && AllPanelsVisible && scroll.ScrollableExtent > 0 && scroll.Current <= scroll_endpoint_distance; /// /// Whether this can be scrolled and is currently scrolled to the end. /// - public bool IsScrolledToEnd => flow.Count > 0 && scroll.ScrollableExtent > 0 && scroll.IsScrolledToEnd(scroll_endpoint_distance); + public bool IsScrolledToEnd => flow.Count > 0 && AllPanelsVisible && scroll.ScrollableExtent > 0 && scroll.IsScrolledToEnd(scroll_endpoint_distance); public bool AllPanelsVisible => flow.All(p => p.IsPresent); From 59aa4dabfda755ffac0a5e9bb4a58d371994394a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 14:33:58 +0900 Subject: [PATCH 838/961] Improve code around background screen handling to read better --- osu.Game/Screens/BackgroundScreenStack.cs | 12 +++++++++--- osu.Game/Screens/OsuScreen.cs | 9 +++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs index 294f23d2ac..9f562a618e 100644 --- a/osu.Game/Screens/BackgroundScreenStack.cs +++ b/osu.Game/Screens/BackgroundScreenStack.cs @@ -17,15 +17,21 @@ namespace osu.Game.Screens Origin = Anchor.Centre; } - public void Push(BackgroundScreen screen) + /// + /// Attempt to push a new background screen to this stack. + /// + /// The screen to attempt to push. + /// Whether the push succeeded. For example, if the existing screen was already of the correct type this will return false. + public bool Push(BackgroundScreen screen) { if (screen == null) - return; + return false; if (EqualityComparer.Default.Equals((BackgroundScreen)CurrentScreen, screen)) - return; + return false; base.Push(screen); + return true; } } } diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index e3fe14a585..9aec2a5c19 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -186,17 +186,14 @@ namespace osu.Game.Screens { applyArrivingDefaults(false); - backgroundStack?.Push(ownedBackground = CreateBackground()); - - background = backgroundStack?.CurrentScreen as BackgroundScreen; - - if (background != ownedBackground) + if (backgroundStack?.Push(ownedBackground = CreateBackground()) != true) { - // background may have not been replaced, at which point we don't want to track the background lifetime. + // If the constructed instance was not actually pushed to the background stack, we don't want to track it unnecessarily. ownedBackground?.Dispose(); ownedBackground = null; } + background = backgroundStack?.CurrentScreen as BackgroundScreen; base.OnEntering(last); } From ddaa95a1ca37e1c264850c4a239e13e83c500cde Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 14:34:18 +0900 Subject: [PATCH 839/961] Fix `pushEditor` function running twice on returning to loader --- osu.Game/Screens/Edit/EditorLoader.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 92420fa7c0..8798a7964b 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -34,10 +34,13 @@ namespace osu.Game.Screens.Edit { base.LogoArriving(logo, resuming); - // the push cannot happen in OnEntering() or similar (even if scheduled), because the transition from main menu will look bad. - // that is because this screen pushing the editor makes it no longer current, and OsuScreen checks if the screen is current - // before enqueueing this screen's LogoArriving onto the logo animation sequence. - pushEditor(); + if (!resuming) + { + // the push cannot happen in OnEntering() or similar (even if scheduled), because the transition from main menu will look bad. + // that is because this screen pushing the editor makes it no longer current, and OsuScreen checks if the screen is current + // before enqueueing this screen's LogoArriving onto the logo animation sequence. + pushEditor(); + } } private void pushEditor() From 7921ad451678925d6bf51628cc6015ac0c69c26b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 14:34:47 +0900 Subject: [PATCH 840/961] Add loading spinner in case load takes longer than expected --- osu.Game/Screens/Edit/EditorLoader.cs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 8798a7964b..499baeec4f 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Menu; namespace osu.Game.Screens.Edit @@ -43,10 +44,16 @@ namespace osu.Game.Screens.Edit } } - private void pushEditor() + [BackgroundDependencyLoader] + private void load() { - this.Push(new Editor(this)); - ValidForResume = false; + AddRangeInternal(new Drawable[] + { + new LoadingSpinner(true) + { + State = { Value = Visibility.Visible }, + } + }); } public void ScheduleDifficultySwitch(BeatmapInfo beatmapInfo) @@ -62,6 +69,12 @@ namespace osu.Game.Screens.Edit }); } + private void pushEditor() + { + this.Push(new Editor(this)); + ValidForResume = false; + } + public void CancelPendingDifficultySwitch() { scheduledDifficultySwitch?.Cancel(); From 9edd010b1d0a52dd233ea41f2e42ea7fb05b808e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 14:34:54 +0900 Subject: [PATCH 841/961] Fix unnecessary background screen transition --- osu.Game/Screens/Edit/EditorLoader.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index 499baeec4f..aec7d32939 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -3,11 +3,14 @@ using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Screens.Menu; +using osu.Game.Screens.Play; namespace osu.Game.Screens.Edit { @@ -15,7 +18,7 @@ namespace osu.Game.Screens.Edit /// Transition screen for the editor. /// Used to avoid backing out to main menu/song select when switching difficulties from within the editor. /// - public class EditorLoader : OsuScreen + public class EditorLoader : ScreenWithBeatmapBackground { public override float BackgroundParallaxAmount => 0.1f; @@ -62,9 +65,16 @@ namespace osu.Game.Screens.Edit ValidForResume = true; this.MakeCurrent(); + scheduledDifficultySwitch = Schedule(() => { Beatmap.Value = beatmapManager.GetWorkingBeatmap(beatmapInfo); + + // This screen is a weird exception to the rule that nothing after song select changes the global beatmap. + // Because of this, we need to update the background stack's beatmap to match. + // If we don't do this, the editor will see a discrepancy and create a new background, along with an unnecessary transition. + ApplyToBackground(b => b.Beatmap = Beatmap.Value); + pushEditor(); }); } From 93da531d135890c7b9addf0570721fdf7e6573da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 14:33:58 +0900 Subject: [PATCH 842/961] Improve code around background screen handling to read better --- osu.Game/Screens/BackgroundScreenStack.cs | 12 +++++++++--- osu.Game/Screens/OsuScreen.cs | 9 +++------ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Screens/BackgroundScreenStack.cs b/osu.Game/Screens/BackgroundScreenStack.cs index 294f23d2ac..9f562a618e 100644 --- a/osu.Game/Screens/BackgroundScreenStack.cs +++ b/osu.Game/Screens/BackgroundScreenStack.cs @@ -17,15 +17,21 @@ namespace osu.Game.Screens Origin = Anchor.Centre; } - public void Push(BackgroundScreen screen) + /// + /// Attempt to push a new background screen to this stack. + /// + /// The screen to attempt to push. + /// Whether the push succeeded. For example, if the existing screen was already of the correct type this will return false. + public bool Push(BackgroundScreen screen) { if (screen == null) - return; + return false; if (EqualityComparer.Default.Equals((BackgroundScreen)CurrentScreen, screen)) - return; + return false; base.Push(screen); + return true; } } } diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index e3fe14a585..9aec2a5c19 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -186,17 +186,14 @@ namespace osu.Game.Screens { applyArrivingDefaults(false); - backgroundStack?.Push(ownedBackground = CreateBackground()); - - background = backgroundStack?.CurrentScreen as BackgroundScreen; - - if (background != ownedBackground) + if (backgroundStack?.Push(ownedBackground = CreateBackground()) != true) { - // background may have not been replaced, at which point we don't want to track the background lifetime. + // If the constructed instance was not actually pushed to the background stack, we don't want to track it unnecessarily. ownedBackground?.Dispose(); ownedBackground = null; } + background = backgroundStack?.CurrentScreen as BackgroundScreen; base.OnEntering(last); } From 4658577b1d272aceba1624b0954ffff11e2cb01f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 7 Sep 2021 15:18:59 +0900 Subject: [PATCH 843/961] Factor in total score calculation time in results screen load --- .../Playlists/PlaylistsResultsScreen.cs | 32 ++++++++++++------- osu.Game/Screens/Ranking/ResultsScreen.cs | 14 ++++---- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs index 2b252f9db7..89bc659f63 100644 --- a/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs +++ b/osu.Game/Screens/OnlinePlay/Playlists/PlaylistsResultsScreen.cs @@ -32,6 +32,9 @@ namespace osu.Game.Screens.OnlinePlay.Playlists [Resolved] private IAPIProvider api { get; set; } + [Resolved] + private ScoreManager scoreManager { get; set; } + public PlaylistsResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem, bool allowRetry, bool allowWatchingReplay = true) : base(score, allowRetry, allowWatchingReplay) { @@ -166,23 +169,28 @@ namespace osu.Game.Screens.OnlinePlay.Playlists /// An optional pivot around which the scores were retrieved. private void performSuccessCallback([NotNull] Action> callback, [NotNull] List scores, [CanBeNull] MultiplayerScores pivot = null) { - var scoreInfos = new List(scores.Select(s => s.CreateScoreInfo(playlistItem))); + var scoreInfos = scores.Select(s => s.CreateScoreInfo(playlistItem)).ToArray(); - // Select a score if we don't already have one selected. - // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). - if (SelectedScore.Value == null) + // Score panels calculate total score before displaying, which can take some time. In order to count that calculation as part of the loading spinner display duration, + // calculate the total scores locally before invoking the success callback. + scoreManager.OrderByTotalScoreAsync(scoreInfos).ContinueWith(_ => Schedule(() => { - Schedule(() => + // Select a score if we don't already have one selected. + // Note: This is done before the callback so that the panel list centres on the selected score before panels are added (eliminating initial scroll). + if (SelectedScore.Value == null) { - // Prefer selecting the local user's score, or otherwise default to the first visible score. - SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault(); - }); - } + Schedule(() => + { + // Prefer selecting the local user's score, or otherwise default to the first visible score. + SelectedScore.Value = scoreInfos.FirstOrDefault(s => s.User.Id == api.LocalUser.Value.Id) ?? scoreInfos.FirstOrDefault(); + }); + } - // Invoke callback to add the scores. Exclude the user's current score which was added previously. - callback.Invoke(scoreInfos.Where(s => s.OnlineScoreID != Score?.OnlineScoreID)); + // Invoke callback to add the scores. Exclude the user's current score which was added previously. + callback.Invoke(scoreInfos.Where(s => s.OnlineScoreID != Score?.OnlineScoreID)); - hideLoadingSpinners(pivot); + hideLoadingSpinners(pivot); + })); } private void hideLoadingSpinners([CanBeNull] MultiplayerScores pivot = null) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index d44d1f2cc9..822ee1cf90 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -52,8 +52,7 @@ namespace osu.Game.Screens.Ranking private Drawable bottomPanel; private Container detachedPanelContainer; - private bool fetchedInitialScores; - private APIRequest nextPageRequest; + private bool lastFetchCompleted; private readonly bool allowRetry; private readonly bool allowWatchingReplay; @@ -191,8 +190,10 @@ namespace osu.Game.Screens.Ranking { base.Update(); - if (fetchedInitialScores && nextPageRequest == null) + if (lastFetchCompleted) { + APIRequest nextPageRequest = null; + if (ScorePanelList.IsScrolledToStart) nextPageRequest = FetchNextPage(-1, fetchScoresCallback); else if (ScorePanelList.IsScrolledToEnd) @@ -200,10 +201,7 @@ namespace osu.Game.Screens.Ranking if (nextPageRequest != null) { - // Scheduled after children to give the list a chance to update its scroll position and not potentially trigger a second request too early. - nextPageRequest.Success += () => ScheduleAfterChildren(() => nextPageRequest = null); - nextPageRequest.Failure += _ => ScheduleAfterChildren(() => nextPageRequest = null); - + lastFetchCompleted = false; api.Queue(nextPageRequest); } } @@ -229,7 +227,7 @@ namespace osu.Game.Screens.Ranking foreach (var s in scores) addScore(s); - fetchedInitialScores = true; + lastFetchCompleted = true; }); public override void OnEntering(IScreen last) From 5b13b566b5151dce86f1f93f54604bbde2f44514 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 15:19:23 +0900 Subject: [PATCH 844/961] Reduce startup overhead during default key binding handling --- .../Database/TestRealmKeyBindingStore.cs | 5 +- osu.Game/Input/RealmKeyBindingStore.cs | 69 ++++++++++--------- osu.Game/OsuGameBase.cs | 5 +- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs index 642ecf00b8..8be74f1a7c 100644 --- a/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs +++ b/osu.Game.Tests/Database/TestRealmKeyBindingStore.cs @@ -11,6 +11,7 @@ using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Input; using osu.Game.Input.Bindings; +using osu.Game.Rulesets; using Realms; namespace osu.Game.Tests.Database @@ -42,7 +43,7 @@ namespace osu.Game.Tests.Database KeyBindingContainer testContainer = new TestKeyBindingContainer(); - keyBindingStore.Register(testContainer); + keyBindingStore.Register(testContainer, Enumerable.Empty()); Assert.That(queryCount(), Is.EqualTo(3)); @@ -66,7 +67,7 @@ namespace osu.Game.Tests.Database { KeyBindingContainer testContainer = new TestKeyBindingContainer(); - keyBindingStore.Register(testContainer); + keyBindingStore.Register(testContainer, Enumerable.Empty()); using (var primaryUsage = realmContextFactory.GetForRead()) { diff --git a/osu.Game/Input/RealmKeyBindingStore.cs b/osu.Game/Input/RealmKeyBindingStore.cs index 9089169877..03cb4031ca 100644 --- a/osu.Game/Input/RealmKeyBindingStore.cs +++ b/osu.Game/Input/RealmKeyBindingStore.cs @@ -46,52 +46,53 @@ namespace osu.Game.Input } /// - /// Register a new type of , adding default bindings from . + /// Register all defaults for this store. /// /// The container to populate defaults from. - public void Register(KeyBindingContainer container) => insertDefaults(container.DefaultKeyBindings); - - /// - /// Register a ruleset, adding default bindings for each of its variants. - /// - /// The ruleset to populate defaults from. - public void Register(RulesetInfo ruleset) - { - var instance = ruleset.CreateInstance(); - - foreach (var variant in instance.AvailableVariants) - insertDefaults(instance.GetDefaultKeyBindings(variant), ruleset.ID, variant); - } - - private void insertDefaults(IEnumerable defaults, int? rulesetId = null, int? variant = null) + /// The rulesets to populate defaults from. + public void Register(KeyBindingContainer container, IEnumerable rulesets) { using (var usage = realmFactory.GetForWrite()) { - // compare counts in database vs defaults - foreach (var defaultsForAction in defaults.GroupBy(k => k.Action)) + // intentionally flattened to a list rather than querying against the IQueryable, as nullable fields being queried against aren't indexed. + // this is much faster as a result. + var existingBindings = usage.Realm.All().ToList(); + + insertDefaults(usage, existingBindings, container.DefaultKeyBindings); + + foreach (var ruleset in rulesets) { - int existingCount = usage.Realm.All().Count(k => k.RulesetID == rulesetId && k.Variant == variant && k.ActionInt == (int)defaultsForAction.Key); - - if (defaultsForAction.Count() <= existingCount) - continue; - - foreach (var k in defaultsForAction.Skip(existingCount)) - { - // insert any defaults which are missing. - usage.Realm.Add(new RealmKeyBinding - { - KeyCombinationString = k.KeyCombination.ToString(), - ActionInt = (int)k.Action, - RulesetID = rulesetId, - Variant = variant - }); - } + var instance = ruleset.CreateInstance(); + foreach (var variant in instance.AvailableVariants) + insertDefaults(usage, existingBindings, instance.GetDefaultKeyBindings(variant), ruleset.ID, variant); } usage.Commit(); } } + private void insertDefaults(RealmContextFactory.RealmUsage usage, List existingBindings, IEnumerable defaults, int? rulesetId = null, int? variant = null) + { + // compare counts in database vs defaults for each action type. + foreach (var defaultsForAction in defaults.GroupBy(k => k.Action)) + { + // avoid performing redundant queries when the database is empty and needs to be re-filled. + int existingCount = existingBindings.Count(k => k.RulesetID == rulesetId && k.Variant == variant && k.ActionInt == (int)defaultsForAction.Key); + + if (defaultsForAction.Count() <= existingCount) + continue; + + // insert any defaults which are missing. + usage.Realm.Add(defaultsForAction.Skip(existingCount).Select(k => new RealmKeyBinding + { + KeyCombinationString = k.KeyCombination.ToString(), + ActionInt = (int)k.Action, + RulesetID = rulesetId, + Variant = variant + })); + } + } + /// /// Keys which should not be allowed for gameplay input purposes. /// diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index 762216e93c..8563c4e171 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -351,10 +351,7 @@ namespace osu.Game base.Content.Add(CreateScalingContainer().WithChildren(mainContent)); KeyBindingStore = new RealmKeyBindingStore(realmFactory); - KeyBindingStore.Register(globalBindings); - - foreach (var r in RulesetStore.AvailableRulesets) - KeyBindingStore.Register(r); + KeyBindingStore.Register(globalBindings, RulesetStore.AvailableRulesets); dependencies.Cache(globalBindings); From 44b1af5ae4419495dcba68f6472b609e43656726 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 15:28:52 +0900 Subject: [PATCH 845/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 8a9bf1b9cd..05367c00f6 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ebe3de6ea4..ae423bac8c 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 1714bae53c..be737392e1 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 61f819b66d16f0d65a14f767cd66d70d13379f00 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 7 Sep 2021 15:51:57 +0900 Subject: [PATCH 846/961] Add COE and better PR condition --- .github/workflows/test-diffcalc.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index d963e49d9f..efa36712be 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -22,12 +22,13 @@ jobs: runs-on: ubuntu-latest if: | - contains(github.event.comment.html_url, '/pull/') && + ${{ github.event.issue.pull_request }} && contains(github.event.comment.body, '!pp check') && ${{ github.event.comment.author_association == 'MEMBER' }} strategy: fail-fast: false + continue-on-error: true matrix: ruleset: - { name: osu, id: 0 } From 842696c388a6b2d1401b4a41fbe1d39af53491d1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 7 Sep 2021 15:54:58 +0900 Subject: [PATCH 847/961] Fix incorrect definition --- .github/workflows/test-diffcalc.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index efa36712be..7728d91152 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -20,6 +20,7 @@ jobs: diffcalc: name: Diffcalc runs-on: ubuntu-latest + continue-on-error: true if: | ${{ github.event.issue.pull_request }} && @@ -28,7 +29,6 @@ jobs: strategy: fail-fast: false - continue-on-error: true matrix: ruleset: - { name: osu, id: 0 } From f3d2d93aa14227f41b6f92e250de9aff5d484164 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 16:09:22 +0900 Subject: [PATCH 848/961] Remove stray newline --- osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs index 34a9610804..631455b727 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneResultsScreen.cs @@ -201,7 +201,6 @@ namespace osu.Game.Tests.Visual.Ranking [Test] public void TestFetchScoresAfterShowingStatistics() - { DelayedFetchResultsScreen screen = null; From b6c80f04b07b33ec6a3504a6ae968c32d724dc75 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 7 Sep 2021 16:44:45 +0900 Subject: [PATCH 849/961] Add "featured artists" filter to beatmap search --- .../UserInterface/TestSceneBeatmapListingSearchControl.cs | 3 ++- osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs | 3 ++- osu.Game/Overlays/BeatmapListing/SearchGeneral.cs | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs index abd1baf0ac..008d91f649 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneBeatmapListingSearchControl.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System.Linq; +using Humanizer; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -73,7 +74,7 @@ namespace osu.Game.Tests.Visual.UserInterface }; control.Query.BindValueChanged(q => query.Text = $"Query: {q.NewValue}", true); - control.General.BindCollectionChanged((u, v) => general.Text = $"General: {(control.General.Any() ? string.Join('.', control.General.Select(i => i.ToString().ToLowerInvariant())) : "")}", true); + control.General.BindCollectionChanged((u, v) => general.Text = $"General: {(control.General.Any() ? string.Join('.', control.General.Select(i => i.ToString().Underscore())) : "")}", true); control.Ruleset.BindValueChanged(r => ruleset.Text = $"Ruleset: {r.NewValue}", true); control.Category.BindValueChanged(c => category.Text = $"Category: {c.NewValue}", true); control.Genre.BindValueChanged(g => genre.Text = $"Genre: {g.NewValue}", true); diff --git a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs index 8ce495e274..ae082ca82e 100644 --- a/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/SearchBeatmapSetsRequest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Humanizer; using JetBrains.Annotations; using osu.Framework.IO.Network; using osu.Game.Extensions; @@ -83,7 +84,7 @@ namespace osu.Game.Online.API.Requests req.AddParameter("q", query); if (General != null && General.Any()) - req.AddParameter("c", string.Join('.', General.Select(e => e.ToString().ToLowerInvariant()))); + req.AddParameter("c", string.Join('.', General.Select(e => e.ToString().Underscore()))); if (ruleset.ID.HasValue) req.AddParameter("m", ruleset.ID.Value.ToString()); diff --git a/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs b/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs index d334b82e88..9387020bdf 100644 --- a/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs +++ b/osu.Game/Overlays/BeatmapListing/SearchGeneral.cs @@ -19,6 +19,10 @@ namespace osu.Game.Overlays.BeatmapListing [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GeneralFollows))] [Description("Subscribed mappers")] - Follows + Follows, + + [LocalisableDescription(typeof(BeatmapsStrings), nameof(BeatmapsStrings.GeneralFeaturedArtists))] + [Description("Featured artists")] + FeaturedArtists } } From d922210d2feda6f03de5717d3ca53e99b4864feb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 16:46:27 +0900 Subject: [PATCH 850/961] Fix `TestSceneDeleteLocalScore` not properly comparing post-delete scores --- .../TestSceneDeleteLocalScore.cs | 19 +++++++------ .../Online/Leaderboards/LeaderboardScore.cs | 27 ++++++++++--------- 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index 8efee2723f..2e30ed9827 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -36,7 +36,7 @@ namespace osu.Game.Tests.Visual.UserInterface private BeatmapManager beatmapManager; private ScoreManager scoreManager; - private readonly List scores = new List(); + private readonly List importedScores = new List(); private BeatmapInfo beatmap; [Cached] @@ -100,11 +100,9 @@ namespace osu.Game.Tests.Visual.UserInterface User = new User { Username = "TestUser" }, }; - scores.Add(scoreManager.Import(score).Result); + importedScores.Add(scoreManager.Import(score).Result); } - scores.Sort(Comparer.Create((s1, s2) => s2.TotalScore.CompareTo(s1.TotalScore))); - return dependencies; } @@ -134,9 +132,14 @@ namespace osu.Game.Tests.Visual.UserInterface [Test] public void TestDeleteViaRightClick() { + ScoreInfo scoreBeingDeleted = null; AddStep("open menu for top score", () => { - InputManager.MoveMouseTo(leaderboard.ChildrenOfType().First()); + var leaderboardScore = leaderboard.ChildrenOfType().First(); + + scoreBeingDeleted = leaderboardScore.Score; + + InputManager.MoveMouseTo(leaderboardScore); InputManager.Click(MouseButton.Right); }); @@ -158,14 +161,14 @@ namespace osu.Game.Tests.Visual.UserInterface InputManager.Click(MouseButton.Left); }); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s != scores[0])); + AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != scoreBeingDeleted.OnlineScoreID)); } [Test] public void TestDeleteViaDatabase() { - AddStep("delete top score", () => scoreManager.Delete(scores[0])); - AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s != scores[0])); + AddStep("delete top score", () => scoreManager.Delete(importedScores[0])); + AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineScoreID != importedScores[0].OnlineScoreID)); } } } diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 934b905a1a..090a4014aa 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -34,6 +34,8 @@ namespace osu.Game.Online.Leaderboards { public const float HEIGHT = 60; + public readonly ScoreInfo Score; + private const float corner_radius = 5; private const float edge_margin = 5; private const float background_alpha = 0.25f; @@ -41,7 +43,6 @@ namespace osu.Game.Online.Leaderboards protected Container RankContainer { get; private set; } - private readonly ScoreInfo score; private readonly int? rank; private readonly bool allowHighlight; @@ -67,7 +68,7 @@ namespace osu.Game.Online.Leaderboards public LeaderboardScore(ScoreInfo score, int? rank, bool allowHighlight = true) { - this.score = score; + this.Score = score; this.rank = rank; this.allowHighlight = allowHighlight; @@ -78,9 +79,9 @@ namespace osu.Game.Online.Leaderboards [BackgroundDependencyLoader] private void load(IAPIProvider api, OsuColour colour, ScoreManager scoreManager) { - var user = score.User; + var user = Score.User; - statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s)).ToList(); + statisticsLabels = GetStatistics(Score).Select(s => new ScoreComponentLabel(s)).ToList(); ClickableAvatar innerAvatar; @@ -198,7 +199,7 @@ namespace osu.Game.Online.Leaderboards { TextColour = Color4.White, GlowColour = Color4Extensions.FromHex(@"83ccfa"), - Current = scoreManager.GetBindableTotalScoreString(score), + Current = scoreManager.GetBindableTotalScoreString(Score), Font = OsuFont.Numeric.With(size: 23), }, RankContainer = new Container @@ -206,7 +207,7 @@ namespace osu.Game.Online.Leaderboards Size = new Vector2(40f, 20f), Children = new[] { - scoreRank = new UpdateableRank(score.Rank) + scoreRank = new UpdateableRank(Score.Rank) { Anchor = Anchor.Centre, Origin = Anchor.Centre, @@ -223,7 +224,7 @@ namespace osu.Game.Online.Leaderboards AutoSizeAxes = Axes.Both, Direction = FillDirection.Horizontal, Spacing = new Vector2(1), - ChildrenEnumerable = score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) + ChildrenEnumerable = Score.Mods.Select(mod => new ModIcon(mod) { Scale = new Vector2(0.375f) }) }, }, }, @@ -389,14 +390,14 @@ namespace osu.Game.Online.Leaderboards { List items = new List(); - if (score.Mods.Length > 0 && modsContainer.Any(s => s.IsHovered) && songSelect != null) - items.Add(new OsuMenuItem("Use these mods", MenuItemType.Highlighted, () => songSelect.Mods.Value = score.Mods)); + if (Score.Mods.Length > 0 && modsContainer.Any(s => s.IsHovered) && songSelect != null) + items.Add(new OsuMenuItem("Use these mods", MenuItemType.Highlighted, () => songSelect.Mods.Value = Score.Mods)); - if (score.Files?.Count > 0) - items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => scoreManager.Export(score))); + if (Score.Files?.Count > 0) + items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => scoreManager.Export(Score))); - if (score.ID != 0) - items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(score)))); + if (Score.ID != 0) + items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); return items.ToArray(); } From a42527b8f553f83923647259c53f9ce53bf67392 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 16:46:40 +0900 Subject: [PATCH 851/961] 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 05367c00f6..7378450c38 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,7 +52,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index ae423bac8c..d80dd075ee 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -36,7 +36,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index be737392e1..8ce757974e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From 91a48084c7b1e71b83f552db216e11f2d1a04143 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 17:25:03 +0900 Subject: [PATCH 852/961] Update asserts in line with framework changes to `PlaybackPosition` --- osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs index e45b8f7dc5..785f31386d 100644 --- a/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs +++ b/osu.Game.Tests/NonVisual/Skinning/LegacySkinAnimationTest.cs @@ -40,10 +40,10 @@ namespace osu.Game.Tests.NonVisual.Skinning assertPlaybackPosition(0); AddStep("set start time to 1000", () => animationTimeReference.AnimationStartTime.Value = 1000); - assertPlaybackPosition(-1000); + assertPlaybackPosition(0); AddStep("set current time to 500", () => animationTimeReference.ManualClock.CurrentTime = 500); - assertPlaybackPosition(-500); + assertPlaybackPosition(0); } private void assertPlaybackPosition(double expectedPosition) From 5ab2f4b38665b0971fff93d752b7213b176934b4 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 7 Sep 2021 17:31:54 +0900 Subject: [PATCH 853/961] Give an orange colour to "featured artists" filter to match web --- .../BeatmapListingSearchControl.cs | 2 +- .../BeatmapSearchGeneralFilterRow.cs | 39 +++++++++++++++++++ .../Overlays/BeatmapListing/FilterTabItem.cs | 4 +- 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 0626f236b8..d1e2ac38df 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -127,7 +127,7 @@ namespace osu.Game.Overlays.BeatmapListing Padding = new MarginPadding { Horizontal = 10 }, Children = new Drawable[] { - generalFilter = new BeatmapSearchMultipleSelectionFilterRow(BeatmapsStrings.ListingSearchFiltersGeneral), + generalFilter = new BeatmapSearchGeneralFilterRow(), modeFilter = new BeatmapSearchRulesetFilterRow(), categoryFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersStatus), genreFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersGenre), diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.cs new file mode 100644 index 0000000000..fb9e1c0420 --- /dev/null +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchGeneralFilterRow.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.Game.Resources.Localisation.Web; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapListing +{ + public class BeatmapSearchGeneralFilterRow : BeatmapSearchMultipleSelectionFilterRow + { + public BeatmapSearchGeneralFilterRow() + : base(BeatmapsStrings.ListingSearchFiltersGeneral) + { + } + + protected override MultipleSelectionFilter CreateMultipleSelectionFilter() => new GeneralFilter(); + + private class GeneralFilter : MultipleSelectionFilter + { + protected override MultipleSelectionFilterTabItem CreateTabItem(SearchGeneral value) + { + if (value == SearchGeneral.FeaturedArtists) + return new FeaturedArtistsTabItem(); + + return new MultipleSelectionFilterTabItem(value); + } + } + + private class FeaturedArtistsTabItem : MultipleSelectionFilterTabItem + { + public FeaturedArtistsTabItem() + : base(SearchGeneral.FeaturedArtists) + { + } + + protected override Color4 GetStateColour() => OverlayColourProvider.Orange.Colour1; + } + } +} diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index 46cb1e822f..9274cf20aa 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -71,10 +71,10 @@ namespace osu.Game.Overlays.BeatmapListing private void updateState() { - text.FadeColour(IsHovered ? colourProvider.Light1 : getStateColour(), 200, Easing.OutQuint); + text.FadeColour(IsHovered ? colourProvider.Light1 : GetStateColour(), 200, Easing.OutQuint); text.Font = text.Font.With(weight: Active.Value ? FontWeight.SemiBold : FontWeight.Regular); } - private Color4 getStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2; + protected virtual Color4 GetStateColour() => Active.Value ? colourProvider.Content1 : colourProvider.Light2; } } From 92f59c10f5108d23d84698d0b5c978726c629b5d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 17:45:21 +0900 Subject: [PATCH 854/961] Remove redundant `this.` in assignment --- osu.Game/Online/Leaderboards/LeaderboardScore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index 090a4014aa..26749a23f9 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -68,7 +68,8 @@ namespace osu.Game.Online.Leaderboards public LeaderboardScore(ScoreInfo score, int? rank, bool allowHighlight = true) { - this.Score = score; + Score = score; + this.rank = rank; this.allowHighlight = allowHighlight; From 3d8faea4b073718900da16d0a0b522fb700aed9d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Sep 2021 18:52:25 +0900 Subject: [PATCH 855/961] Simplify nesting of `OrderByTotalScoreAsync` --- osu.Game/Scoring/ScoreManager.cs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/osu.Game/Scoring/ScoreManager.cs b/osu.Game/Scoring/ScoreManager.cs index 2cda8959f4..81e701f001 100644 --- a/osu.Game/Scoring/ScoreManager.cs +++ b/osu.Game/Scoring/ScoreManager.cs @@ -116,25 +116,20 @@ namespace osu.Game.Scoring { var difficultyCache = difficulties?.Invoke(); - if (difficultyCache == null) - return orderByTotalScore(scores); - - // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. - foreach (var s in scores) + if (difficultyCache != null) { - await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); - cancellationToken.ThrowIfCancellationRequested(); + // Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below. + foreach (var s in scores) + { + await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false); + cancellationToken.ThrowIfCancellationRequested(); + } } - return orderByTotalScore(scores); - - ScoreInfo[] orderByTotalScore(IEnumerable incoming) - { - // We're calling .Result, but this should not be a blocking call due to the above GetDifficultyAsync() calls. - return incoming.OrderByDescending(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken).Result) - .ThenBy(s => s.OnlineScoreID) - .ToArray(); - } + // We're calling .Result, but this should not be a blocking call due to the above GetDifficultyAsync() calls. + return scores.OrderByDescending(s => GetTotalScoreAsync(s, cancellationToken: cancellationToken).Result) + .ThenBy(s => s.OnlineScoreID) + .ToArray(); } /// From 2f42a8461e64ac7f33b75fcb2171b61bc296c99c Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 7 Sep 2021 20:19:07 +0900 Subject: [PATCH 856/961] Fix diffcalc workflow triggering too often --- .github/workflows/test-diffcalc.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-diffcalc.yml b/.github/workflows/test-diffcalc.yml index 7728d91152..4274d01bab 100644 --- a/.github/workflows/test-diffcalc.yml +++ b/.github/workflows/test-diffcalc.yml @@ -23,9 +23,9 @@ jobs: continue-on-error: true if: | - ${{ github.event.issue.pull_request }} && + github.event.issue.pull_request && contains(github.event.comment.body, '!pp check') && - ${{ github.event.comment.author_association == 'MEMBER' }} + (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') strategy: fail-fast: false From f54d5675db79ae378f8623115e984e65446198c3 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 7 Sep 2021 17:06:12 +0100 Subject: [PATCH 857/961] check if user joined requested channel already --- osu.Game/Online/Chat/ChannelManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index d2500f0d7f..43da69db97 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -264,6 +264,11 @@ namespace osu.Game.Online.Chat break; } + // Check if the user has joined requested channel already. + var alreadyJoinedChannel = JoinedChannels.FirstOrDefault(c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name == content); + if (alreadyJoinedChannel != null) + CurrentChannel.Value = alreadyJoinedChannel; + var request = new GetUserRequest(content); request.Success += OpenPrivateChannel; request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); From be9540e53507c83cadd5fc6cdaf18bf5f2495e02 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 7 Sep 2021 17:17:10 +0100 Subject: [PATCH 858/961] fix "key" having wrong url parameter name --- osu.Game/Online/API/Requests/GetUserRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index e49c4ab298..fe954372bf 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -43,7 +43,7 @@ namespace osu.Game.Online.API.Requests Ruleset = ruleset; } - protected override string Target => lookup != null ? $@"users/{lookup}/{Ruleset?.ShortName}?k={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; + protected override string Target => lookup != null ? $@"users/{lookup}/{Ruleset?.ShortName}?key={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; private enum LookupType { From b1c89f761871445a01997c7ac62ba6919eb03055 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 7 Sep 2021 17:22:59 +0100 Subject: [PATCH 859/961] ignore case when search for already joined channel --- osu.Game/Online/Chat/ChannelManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 43da69db97..05f9d244f2 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -265,7 +265,8 @@ namespace osu.Game.Online.Chat } // Check if the user has joined requested channel already. - var alreadyJoinedChannel = JoinedChannels.FirstOrDefault(c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name == content); + var alreadyJoinedChannel = JoinedChannels.FirstOrDefault( + c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase)); if (alreadyJoinedChannel != null) CurrentChannel.Value = alreadyJoinedChannel; From 255f8a9769a0fc1c6ad99df1f5e9a37b2c305bf1 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Tue, 7 Sep 2021 17:25:47 +0100 Subject: [PATCH 860/961] add alias "/msg" (also a command in stable) --- osu.Game/Online/Chat/ChannelManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 05f9d244f2..34c6d048a3 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -257,6 +257,7 @@ namespace osu.Game.Online.Chat break; case "chat": + case "msg": case "query": if (string.IsNullOrWhiteSpace(content)) { From 2097889ce1a83a8ed2415c7fd81e7d990e3ade1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 7 Sep 2021 20:58:14 +0200 Subject: [PATCH 861/961] Add failing test case --- .../Visual/Ranking/TestSceneScorePanelList.cs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs index b2585c0509..6f3b3028be 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneScorePanelList.cs @@ -203,6 +203,71 @@ namespace osu.Game.Tests.Visual.Ranking assertExpandedPanelCentred(); } + [Test] + public void TestKeyboardNavigation() + { + var lowestScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 100 }; + var middleScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 200 }; + var highestScore = new TestScoreInfo(new OsuRuleset().RulesetInfo) { MaxCombo = 300 }; + + createListStep(() => new ScorePanelList()); + + AddStep("add scores and select middle", () => + { + // order of addition purposefully scrambled. + list.AddScore(middleScore); + list.AddScore(lowestScore); + list.AddScore(highestScore); + list.SelectedScore.Value = middleScore; + }); + + assertScoreState(highestScore, false); + assertScoreState(middleScore, true); + assertScoreState(lowestScore, false); + + AddStep("press left", () => InputManager.Key(Key.Left)); + + assertScoreState(highestScore, true); + assertScoreState(middleScore, false); + assertScoreState(lowestScore, false); + assertExpandedPanelCentred(); + + AddStep("press left at start of list", () => InputManager.Key(Key.Left)); + + assertScoreState(highestScore, true); + assertScoreState(middleScore, false); + assertScoreState(lowestScore, false); + assertExpandedPanelCentred(); + + AddStep("press right", () => InputManager.Key(Key.Right)); + + assertScoreState(highestScore, false); + assertScoreState(middleScore, true); + assertScoreState(lowestScore, false); + assertExpandedPanelCentred(); + + AddStep("press right again", () => InputManager.Key(Key.Right)); + + assertScoreState(highestScore, false); + assertScoreState(middleScore, false); + assertScoreState(lowestScore, true); + assertExpandedPanelCentred(); + + AddStep("press right at end of list", () => InputManager.Key(Key.Right)); + + assertScoreState(highestScore, false); + assertScoreState(middleScore, false); + assertScoreState(lowestScore, true); + assertExpandedPanelCentred(); + + AddStep("press left", () => InputManager.Key(Key.Left)); + + assertScoreState(highestScore, false); + assertScoreState(middleScore, true); + assertScoreState(lowestScore, false); + assertExpandedPanelCentred(); + } + private void createListStep(Func creationFunc) { AddStep("create list", () => Child = list = creationFunc().With(d => From 8cc444df5f6a17fbea64c5d2b34d618fbd04530e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 7 Sep 2021 21:14:38 +0200 Subject: [PATCH 862/961] Fix incorrect keyboard navigation order in score panel list --- osu.Game/Screens/Ranking/ScorePanelList.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Ranking/ScorePanelList.cs b/osu.Game/Screens/Ranking/ScorePanelList.cs index a847df344f..d5b8a4c8ea 100644 --- a/osu.Game/Screens/Ranking/ScorePanelList.cs +++ b/osu.Game/Screens/Ranking/ScorePanelList.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -306,18 +307,18 @@ namespace osu.Game.Screens.Ranking if (expandedPanel == null) return base.OnKeyDown(e); - var expandedPanelIndex = flow.GetPanelIndex(expandedPanel.Score); - switch (e.Key) { case Key.Left: - if (expandedPanelIndex > 0) - SelectedScore.Value = flow.Children[expandedPanelIndex - 1].Panel.Score; + var previousScore = flow.GetPreviousScore(expandedPanel.Score); + if (previousScore != null) + SelectedScore.Value = previousScore; return true; case Key.Right: - if (expandedPanelIndex < flow.Count - 1) - SelectedScore.Value = flow.Children[expandedPanelIndex + 1].Panel.Score; + var nextScore = flow.GetNextScore(expandedPanel.Score); + if (nextScore != null) + SelectedScore.Value = nextScore; return true; } @@ -336,6 +337,12 @@ namespace osu.Game.Screens.Ranking public int GetPanelIndex(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Panel.Score != score).Count(); + [CanBeNull] + public ScoreInfo GetPreviousScore(ScoreInfo score) => applySorting(Children).TakeWhile(s => s.Panel.Score != score).LastOrDefault()?.Panel.Score; + + [CanBeNull] + public ScoreInfo GetNextScore(ScoreInfo score) => applySorting(Children).SkipWhile(s => s.Panel.Score != score).ElementAtOrDefault(1)?.Panel.Score; + private IEnumerable applySorting(IEnumerable drawables) => drawables.OfType() .OrderByDescending(GetLayoutPosition) .ThenBy(s => s.Panel.Score.OnlineScoreID); From d8fe98fe12ac5e305c00c78657322b50c337cfa6 Mon Sep 17 00:00:00 2001 From: Ethan Ng Date: Tue, 7 Sep 2021 14:06:23 -0600 Subject: [PATCH 863/961] Fixed grammatical error in ChangelogSupporterPromo --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 508c8399b6..689a7bb4a3 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Changelog }; supportLinkText.AddText("Support further development of osu! and "); - supportLinkText.AddLink("become and osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); + supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); supportLinkText.AddText(" today!"); imageContainer.Children = new Drawable[] From 7543f9dfb0155a3e6232f429add9f04bb7b43231 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 8 Sep 2021 12:21:24 +0900 Subject: [PATCH 864/961] Add featured artist track ID online info --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 6 ++++++ osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index 48f1f0ce68..bf8063cfaf 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -90,6 +90,12 @@ namespace osu.Game.Beatmaps /// The song language of this beatmap set. /// public BeatmapSetOnlineLanguage Language { get; set; } + + /// + /// The song ID of this beatmap set. + /// Non-null only if the song is from a featured artist. + /// + public int? TrackId { get; set; } } public class BeatmapSetOnlineGenre diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index 45d9c9405f..f653a654ca 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"ratings")] private int[] ratings { get; set; } + [JsonProperty(@"track_id")] + private int? trackId { get; set; } + [JsonProperty(@"user_id")] private int creatorId { @@ -106,7 +109,8 @@ namespace osu.Game.Online.API.Requests.Responses Availability = availability, HasFavourited = hasFavourited, Genre = genre, - Language = language + Language = language, + TrackId = trackId }, }; From 81c9d831f496702d2536b7fb27c04b96a9f3a24f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 13:26:07 +0900 Subject: [PATCH 865/961] Cache reflection portion of `SettingSource` lookups Fixes the mod-related overhead portion of https://github.com/ppy/osu/issues/14638. There's still a significant performance issue that will be addressed separately. --- .../Configuration/SettingSourceAttribute.cs | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index f373e59417..4fff81b587 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -167,18 +167,7 @@ namespace osu.Game.Configuration } } - public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this object obj) - { - foreach (var property in obj.GetType().GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance)) - { - var attr = property.GetCustomAttribute(true); - - if (attr == null) - continue; - - yield return (attr, property); - } - } + public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this T obj) => SettingSourceCache.SettingSourceProperties; public static ICollection<(SettingSourceAttribute, PropertyInfo)> GetOrderedSettingsSourceProperties(this object obj) => obj.GetSettingsSourceProperties() @@ -196,5 +185,14 @@ namespace osu.Game.Configuration protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 100); } } + + private static class SettingSourceCache + { + public static (SettingSourceAttribute, PropertyInfo)[] SettingSourceProperties { get; } = + typeof(T).GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) + .Select(property => (property.GetCustomAttribute(), property)) + .Where(pair => pair.Item1 != null) + .ToArray(); + } } } From f96be2cab89cd11e08325e4e22f1a8a45a6ea308 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 8 Sep 2021 13:27:20 +0900 Subject: [PATCH 866/961] Add featured artist marker to beatmap set listing and overlay --- .../BeatmapListing/Panels/GridBeatmapPanel.cs | 28 +++++++++++--- .../BeatmapListing/Panels/ListBeatmapPanel.cs | 26 +++++++++++-- .../BeatmapSet/BeatmapSetBadgePill.cs | 32 ++++++++++++++++ .../BeatmapSet/BeatmapSetHeaderContent.cs | 23 +++++++++-- .../BeatmapSet/ExplicitContentBeatmapPill.cs | 38 +++++-------------- .../BeatmapSet/FeaturedArtistBeatmapPill.cs | 27 +++++++++++++ 6 files changed, 133 insertions(+), 41 deletions(-) create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs create mode 100644 osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs diff --git a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs index 4d5c387c4a..c078127353 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/GridBeatmapPanel.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels private const float horizontal_padding = 10; private const float vertical_padding = 5; - private FillFlowContainer bottomPanel, statusContainer, titleContainer; + private FillFlowContainer bottomPanel, statusContainer, titleContainer, artistContainer; private PlayButton playButton; private Box progressBar; @@ -89,11 +89,19 @@ namespace osu.Game.Overlays.BeatmapListing.Panels }, } }, - new OsuSpriteText + artistContainer = new FillFlowContainer { - Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), - Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) - }, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), + Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) + } + } + } }, }, new Container @@ -213,6 +221,16 @@ namespace osu.Game.Overlays.BeatmapListing.Panels }); } + if (SetInfo.OnlineInfo?.TrackId != null) + { + artistContainer.Add(new FeaturedArtistBeatmapPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 10f, Top = 2f }, + }); + } + if (SetInfo.OnlineInfo?.HasVideo ?? false) { statusContainer.Add(new IconPill(FontAwesome.Solid.Film)); diff --git a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs index 00ffd168c1..5011749c5f 100644 --- a/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs +++ b/osu.Game/Overlays/BeatmapListing/Panels/ListBeatmapPanel.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.BeatmapListing.Panels private const float vertical_padding = 5; private const float height = 70; - private FillFlowContainer statusContainer, titleContainer; + private FillFlowContainer statusContainer, titleContainer, artistContainer; protected BeatmapPanelDownloadButton DownloadButton; private PlayButton playButton; private Box progressBar; @@ -112,10 +112,18 @@ namespace osu.Game.Overlays.BeatmapListing.Panels }, } }, - new OsuSpriteText + artistContainer = new FillFlowContainer { - Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), - Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Children = new[] + { + new OsuSpriteText + { + Text = new RomanisableString(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist), + Font = OsuFont.GetFont(weight: FontWeight.Bold, italics: true) + }, + }, }, } }, @@ -227,6 +235,16 @@ namespace osu.Game.Overlays.BeatmapListing.Panels }); } + if (SetInfo.OnlineInfo?.TrackId != null) + { + artistContainer.Add(new FeaturedArtistBeatmapPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Margin = new MarginPadding { Left = 10f, Top = 2f }, + }); + } + if (SetInfo.OnlineInfo?.HasVideo ?? false) { statusContainer.Add(new IconPill(FontAwesome.Solid.Film) { IconSize = new Vector2(20) }); diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs new file mode 100644 index 0000000000..15c691103a --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapSetBadgePill : CircularContainer + { + public BeatmapSetBadgePill() + { + AutoSizeAxes = Axes.Both; + Masking = true; + } + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] OsuColour colours, [CanBeNull] OverlayColourProvider colourProvider) + { + Add(new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider?.Background5 ?? colours?.Gray2 ?? Color4.DarkGray, + }); + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs index a61640a02e..c3b6444a24 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetHeaderContent.cs @@ -37,6 +37,7 @@ namespace osu.Game.Overlays.BeatmapSet private readonly OsuSpriteText title, artist; private readonly AuthorInfo author; private readonly ExplicitContentBeatmapPill explicitContentPill; + private readonly FeaturedArtistBeatmapPill featuredArtistPill; private readonly FillFlowContainer downloadButtonsContainer; private readonly BeatmapAvailability beatmapAvailability; private readonly BeatmapSetOnlineStatusPill onlineStatusPill; @@ -129,10 +130,25 @@ namespace osu.Game.Overlays.BeatmapSet } } }, - artist = new OsuSpriteText + new FillFlowContainer { - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true), - Margin = new MarginPadding { Bottom = 20 } + Direction = FillDirection.Horizontal, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Bottom = 20 }, + Children = new Drawable[] + { + artist = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Medium, italics: true), + }, + featuredArtistPill = new FeaturedArtistBeatmapPill + { + Alpha = 0f, + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Margin = new MarginPadding { Left = 10 } + } + } }, new Container { @@ -233,6 +249,7 @@ namespace osu.Game.Overlays.BeatmapSet artist.Text = new RomanisableString(setInfo.NewValue.Metadata.ArtistUnicode, setInfo.NewValue.Metadata.Artist); explicitContentPill.Alpha = setInfo.NewValue.OnlineInfo.HasExplicitContent ? 1 : 0; + featuredArtistPill.Alpha = setInfo.NewValue.OnlineInfo.TrackId != null ? 1 : 0; onlineStatusPill.FadeIn(500, Easing.OutQuint); onlineStatusPill.Status = setInfo.NewValue.OnlineInfo.Status; diff --git a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs index ba78592ed2..60fa3ea900 100644 --- a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs +++ b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs @@ -4,44 +4,24 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class ExplicitContentBeatmapPill : CompositeDrawable + public class ExplicitContentBeatmapPill : BeatmapSetBadgePill { - public ExplicitContentBeatmapPill() + [BackgroundDependencyLoader] + private void load() { - AutoSizeAxes = Axes.Both; - } - - [BackgroundDependencyLoader(true)] - private void load(OsuColour colours, OverlayColourProvider colourProvider) - { - InternalChild = new CircularContainer + Add(new OsuSpriteText { - Masking = true, - AutoSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider?.Background5 ?? colours.Gray2, - }, - new OsuSpriteText - { - Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, - Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), - Colour = OverlayColourProvider.Orange.Colour2, - } - } - }; + Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, + Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Orange.Colour2, + }); } } } diff --git a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs new file mode 100644 index 0000000000..7facc2953a --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs @@ -0,0 +1,27 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class FeaturedArtistBeatmapPill : BeatmapSetBadgePill + { + [BackgroundDependencyLoader] + private void load() + { + Add(new OsuSpriteText + { + Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, + Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Blue.Colour1 + }); + } + } +} From 8745d299dc36f4817e73729d5ead419689397046 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 8 Sep 2021 13:27:45 +0900 Subject: [PATCH 867/961] Add visual tests for featured artist markers --- .../Online/TestSceneBeatmapSetOverlay.cs | 11 +++++++++++ .../Visual/Online/TestSceneDirectPanel.cs | 19 ++++++++++++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index edc1696456..de7e4075f3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -246,6 +246,17 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestFeaturedBeatmap() + { + AddStep("show featured map", () => + { + var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + beatmapSet.OnlineInfo.TrackId = 1; + overlay.ShowBeatmapSet(beatmapSet); + }); + } + [Test] public void TestHide() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs index fd5f306e07..722010ace2 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneDirectPanel.cs @@ -99,16 +99,23 @@ namespace osu.Game.Tests.Visual.Online [BackgroundDependencyLoader] private void load(RulesetStore rulesets) { - var normal = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + var normal = getBeatmapSet(); normal.OnlineInfo.HasVideo = true; normal.OnlineInfo.HasStoryboard = true; var undownloadable = getUndownloadableBeatmapSet(); var manyDifficulties = getManyDifficultiesBeatmapSet(rulesets); - var explicitMap = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + var explicitMap = getBeatmapSet(); explicitMap.OnlineInfo.HasExplicitContent = true; + var featuredMap = getBeatmapSet(); + featuredMap.OnlineInfo.TrackId = 1; + + var explicitFeaturedMap = getBeatmapSet(); + explicitFeaturedMap.OnlineInfo.HasExplicitContent = true; + explicitFeaturedMap.OnlineInfo.TrackId = 2; + Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, @@ -125,13 +132,19 @@ namespace osu.Game.Tests.Visual.Online new GridBeatmapPanel(undownloadable), new GridBeatmapPanel(manyDifficulties), new GridBeatmapPanel(explicitMap), + new GridBeatmapPanel(featuredMap), + new GridBeatmapPanel(explicitFeaturedMap), new ListBeatmapPanel(normal), new ListBeatmapPanel(undownloadable), new ListBeatmapPanel(manyDifficulties), - new ListBeatmapPanel(explicitMap) + new ListBeatmapPanel(explicitMap), + new ListBeatmapPanel(featuredMap), + new ListBeatmapPanel(explicitFeaturedMap) }, }, }; + + BeatmapSetInfo getBeatmapSet() => CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; } } } From 217ca754aef221d955d25203d7aca757594ed184 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Wed, 8 Sep 2021 13:45:05 +0900 Subject: [PATCH 868/961] Add sound for team swaps --- .../Multiplayer/Participants/TeamDisplay.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 351b9b3673..915cf30963 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -3,6 +3,8 @@ using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Graphics; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Containers; @@ -22,6 +24,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants private Drawable box; + private Sample sampleTeamSwap; + [Resolved] private OsuColour colours { get; set; } @@ -39,7 +43,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants } [BackgroundDependencyLoader] - private void load() + private void load(AudioManager audio) { box = new Container { @@ -72,6 +76,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants { InternalChild = box; } + + sampleTeamSwap = audio.Samples.Get(@"Multiplayer/team-swap"); } private void changeTeam() @@ -99,6 +105,9 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants if (newTeam == displayedTeam) return; + if (newTeam != null && displayedTeam != null) + sampleTeamSwap?.Play(); + displayedTeam = newTeam; if (displayedTeam != null) From 9637326f0c8be64912660890f59f3175a68b908a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 8 Sep 2021 15:50:19 +0900 Subject: [PATCH 869/961] Allow customizing link style by override in `LinkFlowContainer` --- .../Graphics/Containers/LinkFlowContainer.cs | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs index 85ef779e48..21c1d70d45 100644 --- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs +++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs @@ -87,23 +87,25 @@ namespace osu.Game.Graphics.Containers private void createLink(IEnumerable drawables, LinkDetails link, string tooltipText, Action action = null) { - AddInternal(new DrawableLinkCompiler(drawables.OfType().ToList()) + var linkCompiler = CreateLinkCompiler(drawables.OfType()); + linkCompiler.RelativeSizeAxes = Axes.Both; + linkCompiler.TooltipText = tooltipText; + linkCompiler.Action = () => { - RelativeSizeAxes = Axes.Both, - TooltipText = tooltipText, - Action = () => - { - if (action != null) - action(); - else if (game != null) - game.HandleLink(link); - // fallback to handle cases where OsuGame is not available, ie. tournament client. - else if (link.Action == LinkAction.External) - host.OpenUrlExternally(link.Argument); - }, - }); + if (action != null) + action(); + else if (game != null) + game.HandleLink(link); + // fallback to handle cases where OsuGame is not available, ie. tournament client. + else if (link.Action == LinkAction.External) + host.OpenUrlExternally(link.Argument); + }; + + AddInternal(linkCompiler); } + protected virtual DrawableLinkCompiler CreateLinkCompiler(IEnumerable parts) => new DrawableLinkCompiler(parts); + // We want the compilers to always be visible no matter where they are, so RelativeSizeAxes is used. // However due to https://github.com/ppy/osu-framework/issues/2073, it's possible for the compilers to be relative size in the flow's auto-size axes - an unsupported operation. // Since the compilers don't display any content and don't affect the layout, it's simplest to exclude them from the flow. From d417f03a39d22f7e5b39a31735659fb531f354be Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 8 Sep 2021 15:52:01 +0900 Subject: [PATCH 870/961] Simplify link style customization code --- .../Overlays/Changelog/ChangelogSupporterPromo.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 689a7bb4a3..c2b855a0f8 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -126,7 +126,7 @@ namespace osu.Game.Overlays.Changelog }; supportLinkText.AddText("Support further development of osu! and "); - supportLinkText.AddLink("become an osu!supporter", "https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); + supportLinkText.AddLink("become an osu!supporter", @"https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); supportLinkText.AddText(" today!"); imageContainer.Children = new Drawable[] @@ -170,27 +170,18 @@ namespace osu.Game.Overlays.Changelog { } - public new void AddLink(string text, string url, Action creationParameters) => - AddInternal(new SupporterPromoLinkCompiler(AddText(text, creationParameters)) { Url = url }); + protected override DrawableLinkCompiler CreateLinkCompiler(IEnumerable parts) => new SupporterPromoLinkCompiler(parts); private class SupporterPromoLinkCompiler : DrawableLinkCompiler { - [Resolved(CanBeNull = true)] - private OsuGame game { get; set; } - - public string Url; - public SupporterPromoLinkCompiler(IEnumerable parts) : base(parts) { - RelativeSizeAxes = Axes.Both; } [BackgroundDependencyLoader] private void load(OsuColour colour) { - TooltipText = Url; - Action = () => game?.HandleLink(Url); IdleColour = colour.PinkDark; HoverColour = Color4.White; } From 037b9cfb59d189576ad6f0cd3ec8ed04964d4968 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 16:53:23 +0900 Subject: [PATCH 871/961] Load `DrawableLoungRoom`s asynchronously --- .../OnlinePlay/Lounge/Components/RoomsContainer.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 76cb02199b..8e3c74aba9 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -64,9 +64,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override void LoadComplete() { - rooms.CollectionChanged += roomsChanged; roomManager.RoomsUpdated += updateSorting; + rooms.CollectionChanged += roomsChanged; rooms.BindTo(roomManager.Rooms); Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true); @@ -108,10 +108,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void addRooms(IEnumerable rooms) { - foreach (var room in rooms) - roomFlow.Add(new DrawableLoungeRoom(room) { SelectedRoom = { BindTarget = SelectedRoom } }); + LoadComponentsAsync(rooms.Select(room => + new DrawableLoungeRoom(room) { SelectedRoom = { BindTarget = SelectedRoom } }), rooms => + { + // check against rooms collection to ensure the room wasn't removed since this async load started. + roomFlow.AddRange(rooms.Where(r => this.rooms.Contains(r.Room))); - applyFilterCriteria(Filter?.Value); + applyFilterCriteria(Filter?.Value); + }); } private void removeRooms(IEnumerable rooms) From bebb9d7e675f18e7667ab202335efcb542a1f32b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 17:13:12 +0900 Subject: [PATCH 872/961] Wrap main content of `DrawableRoom` --- .../Lounge/Components/DrawableRoom.cs | 286 +++++++++--------- 1 file changed, 146 insertions(+), 140 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 106211c833..964a9eddfb 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -43,6 +43,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private PasswordProtectedIcon passwordIcon; private EndDateInfo endDateInfo; + private DelayedLoadWrapper wrapper; + public DrawableRoom(Room room) { Room = room; @@ -75,155 +77,156 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { d.RelativeSizeAxes = Axes.Both; }), - new Container - { - Name = @"Room content", - RelativeSizeAxes = Axes.Both, - // This negative padding resolves 1px gaps between this background and the background above. - Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, - Child = new Container + wrapper = new DelayedLoadWrapper(() => + new Container { + Name = @"Room content", RelativeSizeAxes = Axes.Both, - Masking = true, - CornerRadius = CORNER_RADIUS, - Children = new Drawable[] + // This negative padding resolves 1px gaps between this background and the background above. + Padding = new MarginPadding { Left = 20, Vertical = -0.5f }, + Child = new Container { - new GridContainer + RelativeSizeAxes = Axes.Both, + Masking = true, + CornerRadius = CORNER_RADIUS, + Children = new Drawable[] { - RelativeSizeAxes = Axes.Both, - ColumnDimensions = new[] + new GridContainer { - new Dimension(GridSizeMode.Relative, 0.2f) - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colours.Background5, - }, - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f)) - }, - } - } - }, - new Container - { - Name = @"Left details", - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding - { - Left = 20, - Vertical = 5 - }, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] - { - new RoomStatusPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - specialCategoryPill = new RoomSpecialCategoryPill - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft - }, - endDateInfo = new EndDateInfo - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 3 }, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new RoomNameText(), - new RoomHostText(), - } - } - }, + new Dimension(GridSizeMode.Relative, 0.2f) }, - new FillFlowContainer + Content = new[] { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - AutoSizeAxes = Axes.Both, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new Drawable[] + new Drawable[] { - new PlaylistCountPill + new Box { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, + RelativeSizeAxes = Axes.Both, + Colour = colours.Background5, }, - new StarRatingRangeDisplay + new Box { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Scale = new Vector2(0.8f) + RelativeSizeAxes = Axes.Both, + Colour = ColourInfo.GradientHorizontal(colours.Background5, colours.Background5.Opacity(0.3f)) + }, + } + } + }, + new Container + { + Name = @"Left details", + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding + { + Left = 20, + Vertical = 5 + }, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new RoomStatusPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + specialCategoryPill = new RoomSpecialCategoryPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft + }, + endDateInfo = new EndDateInfo + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Top = 3 }, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new RoomNameText(), + new RoomHostText(), + } + } + }, + }, + new FillFlowContainer + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new Drawable[] + { + new PlaylistCountPill + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + }, + new StarRatingRangeDisplay + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Scale = new Vector2(0.8f) + } } } } - } - }, - new FillFlowContainer - { - Name = "Right content", - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - AutoSizeAxes = Axes.X, - RelativeSizeAxes = Axes.Y, - Spacing = new Vector2(5), - Padding = new MarginPadding - { - Right = 10, - Vertical = 20, }, - Children = new Drawable[] + new FillFlowContainer { - ButtonsContainer = new Container + Name = "Right content", + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + AutoSizeAxes = Axes.X, + RelativeSizeAxes = Axes.Y, + Spacing = new Vector2(5), + Padding = new MarginPadding { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X + Right = 10, + Vertical = 20, }, - recentParticipantsList = new RecentParticipantsList + Children = new Drawable[] { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - NumberOfCircles = NumberOfAvatars + ButtonsContainer = new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }, + recentParticipantsList = new RecentParticipantsList + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + NumberOfCircles = NumberOfAvatars + } } - } + }, + passwordIcon = new PasswordProtectedIcon { Alpha = 0 } }, - passwordIcon = new PasswordProtectedIcon { Alpha = 0 } }, - }, - }, + }, 0) }; } @@ -231,23 +234,26 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components { base.LoadComplete(); - roomCategory.BindTo(Room.Category); - roomCategory.BindValueChanged(c => + wrapper.DelayedLoadComplete += _ => { - if (c.NewValue == RoomCategory.Spotlight) - specialCategoryPill.Show(); - else - specialCategoryPill.Hide(); - }, true); + roomCategory.BindTo(Room.Category); + roomCategory.BindValueChanged(c => + { + if (c.NewValue == RoomCategory.Spotlight) + specialCategoryPill.Show(); + else + specialCategoryPill.Hide(); + }, true); - roomType.BindTo(Room.Type); - roomType.BindValueChanged(t => - { - endDateInfo.Alpha = t.NewValue == MatchType.Playlists ? 1 : 0; - }, true); + roomType.BindTo(Room.Type); + roomType.BindValueChanged(t => + { + endDateInfo.Alpha = t.NewValue == MatchType.Playlists ? 1 : 0; + }, true); - hasPassword.BindTo(Room.HasPassword); - hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true); + hasPassword.BindTo(Room.HasPassword); + hasPassword.BindValueChanged(v => passwordIcon.Alpha = v.NewValue ? 1 : 0, true); + }; } protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) From 3e41d8b32e146285b610b93b9f2f6e2d5e69221c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 17:30:13 +0900 Subject: [PATCH 873/961] Reduce initial fade transforms --- osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs index 6dc3cd18c5..a13d67a0c9 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/DrawableLoungeRoom.cs @@ -83,12 +83,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge { base.LoadComplete(); - if (matchingFilter) - this.FadeInFromZero(transition_duration); - else - Alpha = 0; + Alpha = matchingFilter ? 1 : 0; + selectionBox.Alpha = SelectedRoom.Value == Room ? 1 : 0; - SelectedRoom.BindValueChanged(updateSelectedRoom, true); + SelectedRoom.BindValueChanged(updateSelectedRoom); } private void updateSelectedRoom(ValueChangedEvent selected) From 7ed995fbc504f67bc009d0a79ede13e985e0589d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 19:38:47 +0900 Subject: [PATCH 874/961] Add test with many rooms displayed --- .../Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs index dafa8300f6..5c248163d7 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsLoungeSubScreen.cs @@ -32,6 +32,12 @@ namespace osu.Game.Tests.Visual.Playlists private RoomsContainer roomsContainer => loungeScreen.ChildrenOfType().First(); + [Test] + public void TestManyRooms() + { + AddStep("add rooms", () => RoomManager.AddRooms(500)); + } + [Test] public void TestScrollByDraggingRooms() { From 7941240a007696d64f77c62afd561e2119c7808e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 20:51:05 +0900 Subject: [PATCH 875/961] Revert "Load `DrawableLoungRoom`s asynchronously" This reverts commit 0b55bb6913fbf05ebb8ecadfe711084d6797efe0. --- .../OnlinePlay/Lounge/Components/RoomsContainer.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs index 8e3c74aba9..76cb02199b 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/RoomsContainer.cs @@ -64,9 +64,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components protected override void LoadComplete() { + rooms.CollectionChanged += roomsChanged; roomManager.RoomsUpdated += updateSorting; - rooms.CollectionChanged += roomsChanged; rooms.BindTo(roomManager.Rooms); Filter?.BindValueChanged(criteria => applyFilterCriteria(criteria.NewValue), true); @@ -108,14 +108,10 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components private void addRooms(IEnumerable rooms) { - LoadComponentsAsync(rooms.Select(room => - new DrawableLoungeRoom(room) { SelectedRoom = { BindTarget = SelectedRoom } }), rooms => - { - // check against rooms collection to ensure the room wasn't removed since this async load started. - roomFlow.AddRange(rooms.Where(r => this.rooms.Contains(r.Room))); + foreach (var room in rooms) + roomFlow.Add(new DrawableLoungeRoom(room) { SelectedRoom = { BindTarget = SelectedRoom } }); - applyFilterCriteria(Filter?.Value); - }); + applyFilterCriteria(Filter?.Value); } private void removeRooms(IEnumerable rooms) From 136573982c114ec5b626e92f76510bd0fdf253b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 20:51:16 +0900 Subject: [PATCH 876/961] Add fade in and fix incorrect wrapper bounds --- .../Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 964a9eddfb..3a3c07fb19 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -227,6 +227,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, }, }, 0) + { + RelativeSizeAxes = Axes.Both, + } }; } @@ -236,6 +239,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components wrapper.DelayedLoadComplete += _ => { + wrapper.FadeInFromZero(200); + roomCategory.BindTo(Room.Category); roomCategory.BindValueChanged(c => { From a622a0b6609bd676cf23a6d536cbc24d998aadf4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Sep 2021 23:07:53 +0900 Subject: [PATCH 877/961] Use a more traditional method of caching --- .../Configuration/SettingSourceAttribute.cs | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 4fff81b587..4346a583ec 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -167,7 +168,30 @@ namespace osu.Game.Configuration } } - public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this T obj) => SettingSourceCache.SettingSourceProperties; + private static readonly ConcurrentDictionary> property_info_cache = new ConcurrentDictionary>(); + + public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this object obj) + { + var type = obj.GetType(); + + if (!property_info_cache.TryGetValue(type, out var properties)) + property_info_cache[type] = properties = getSettingsSourceProperties(type); + + return properties; + } + + private static IEnumerable<(SettingSourceAttribute, PropertyInfo)> getSettingsSourceProperties(Type type) + { + foreach (var property in type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance)) + { + var attr = property.GetCustomAttribute(true); + + if (attr == null) + continue; + + yield return (attr, property); + } + } public static ICollection<(SettingSourceAttribute, PropertyInfo)> GetOrderedSettingsSourceProperties(this object obj) => obj.GetSettingsSourceProperties() @@ -185,14 +209,5 @@ namespace osu.Game.Configuration protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 100); } } - - private static class SettingSourceCache - { - public static (SettingSourceAttribute, PropertyInfo)[] SettingSourceProperties { get; } = - typeof(T).GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance) - .Select(property => (property.GetCustomAttribute(), property)) - .Where(pair => pair.Item1 != null) - .ToArray(); - } } } From 6fc46792d3fecfdd78158f5047ca62d4f9bc65a6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 00:39:54 +0900 Subject: [PATCH 878/961] Fix test regressions --- .../Visual/Multiplayer/TestSceneDrawableRoom.cs | 2 ++ .../OnlinePlay/Lounge/Components/DrawableRoom.cs | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs index 3973dc57b2..b1f5781f6f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoom.cs @@ -130,6 +130,8 @@ namespace osu.Game.Tests.Visual.Multiplayer Type = { Value = MatchType.HeadToHead }, })); + AddUntilStep("wait for panel load", () => drawableRoom.ChildrenOfType().Any()); + AddAssert("password icon hidden", () => Precision.AlmostEquals(0, drawableRoom.ChildrenOfType().Single().Alpha)); AddStep("set password", () => room.Password.Value = "password"); diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs index 3a3c07fb19..80070aa6ba 100644 --- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs +++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs @@ -65,6 +65,14 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components [BackgroundDependencyLoader] private void load(OverlayColourProvider colours) { + ButtonsContainer = new Container + { + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X + }; + InternalChildren = new[] { // This resolves internal 1px gaps due to applying the (parenting) corner radius and masking across multiple filling background sprites. @@ -208,13 +216,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components }, Children = new Drawable[] { - ButtonsContainer = new Container - { - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - RelativeSizeAxes = Axes.Y, - AutoSizeAxes = Axes.X - }, + ButtonsContainer, recentParticipantsList = new RecentParticipantsList { Anchor = Anchor.CentreRight, From ba99a808af624d4a2ae9c4a77dc0f3be8a25f535 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 01:21:19 +0900 Subject: [PATCH 879/961] Use a decoupled clock for triangles intro to avoid startup freezes on broken audio device --- osu.Game/Screens/Menu/IntroScreen.cs | 2 +- osu.Game/Screens/Menu/IntroTriangles.cs | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index 07a94fb97e..ac4a53f4a9 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -165,7 +165,7 @@ namespace osu.Game.Screens.Menu protected override BackgroundScreen CreateBackground() => new BackgroundScreenBlack(); - protected void StartTrack() + protected virtual void StartTrack() { // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu. if (UsingThemedIntro) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 0ea83fe5e7..69333d4a12 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Menu private Sample welcome; + private DecoupleableInterpolatingFramedClock decoupledClock; + [BackgroundDependencyLoader] private void load() { @@ -56,10 +58,18 @@ namespace osu.Game.Screens.Menu { PrepareMenuLoad(); + decoupledClock = new DecoupleableInterpolatingFramedClock + { + IsCoupled = false + }; + + if (UsingThemedIntro) + decoupledClock.ChangeSource(Track); + LoadComponentAsync(new TrianglesIntroSequence(logo, background) { RelativeSizeAxes = Axes.Both, - Clock = new FramedClock(UsingThemedIntro ? Track : null), + Clock = decoupledClock, LoadMenu = LoadMenu }, t => { @@ -78,6 +88,12 @@ namespace osu.Game.Screens.Menu background.FadeOut(100); } + protected override void StartTrack() + { + if (UsingThemedIntro) + decoupledClock.Start(); + } + private class TrianglesIntroSequence : CompositeDrawable { private readonly OsuLogo logo; From 9b05bf3a2cf8db1fc9c18e06cbe9f7952110bef0 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Sep 2021 11:43:59 -0700 Subject: [PATCH 880/961] Fix volume meter not being highlighted when hovering before show --- osu.Game/Overlays/Volume/VolumeMeter.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Volume/VolumeMeter.cs b/osu.Game/Overlays/Volume/VolumeMeter.cs index f4cbbf5a00..7249dd77e5 100644 --- a/osu.Game/Overlays/Volume/VolumeMeter.cs +++ b/osu.Game/Overlays/Volume/VolumeMeter.cs @@ -355,6 +355,12 @@ namespace osu.Game.Overlays.Volume return base.OnMouseMove(e); } + protected override bool OnHover(HoverEvent e) + { + State = SelectionState.Selected; + return false; + } + protected override void OnHoverLost(HoverLostEvent e) { } From 2888623bdb417a707ddb76939d27f6b7d65bf985 Mon Sep 17 00:00:00 2001 From: Emil Olesen Date: Wed, 8 Sep 2021 22:02:24 +0200 Subject: [PATCH 881/961] Extended the width of the ResetSectionButton to be equal to Content.Width. Fixes #14685 --- .../Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index ef5ccae1a0..2e49671669 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { Text = InputSettingsStrings.ResetSectionButton; RelativeSizeAxes = Axes.X; - Width = 0.5f; + Width = Content.Width; Anchor = Anchor.TopCentre; Origin = Anchor.TopCentre; Margin = new MarginPadding { Top = 15 }; From 46a2e6ce424b03a6a411ef485ee26352c5d80e65 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Sep 2021 14:57:38 -0700 Subject: [PATCH 882/961] Specify minimum windows version --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8f922f74a7..d1ad63663f 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,12 @@ If you are looking to install or test osu! without setting up a development envi **Latest build:** -| [Windows (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) +| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | ------------- | ------------- | ------------- | ------------- | ------------- | - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. -- When running on Windows 7 or 8.1, *[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net50&pivots=os-windows#dependencies)** may be required to correctly run .NET 5 applications if your operating system is not up-to-date with the latest service packs. +- When running on Windows 8.1, *[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net50&pivots=os-windows#dependencies)** may be required to correctly run .NET 5 applications if your operating system is not up-to-date with the latest service packs. If your platform is not listed above, there is still a chance you can manually build it by following the instructions below. ## Developing a custom ruleset From ff4d890a441e198e77cd508a36a218ea78760640 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Sep 2021 15:01:53 -0700 Subject: [PATCH 883/961] Normalise format of listed OSes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1ad63663f..f4313eea8c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi **Latest build:** -| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS(iOS 10+)](https://osu.ppy.sh/home/testflight) | [Android (5+)](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) +| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | ------------- | ------------- | ------------- | ------------- | ------------- | - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. From 31bb2055f9b825b7afc1a0f4e660d4451d66fad3 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Sep 2021 15:06:39 -0700 Subject: [PATCH 884/961] Remove stray space on table --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f4313eea8c..9dd5280d13 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ If you are looking to install or test osu! without setting up a development envi **Latest build:** -| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) +| [Windows 8.1+ (x64)](https://github.com/ppy/osu/releases/latest/download/install.exe) | [macOS 10.12+](https://github.com/ppy/osu/releases/latest/download/osu.app.zip) | [Linux (x64)](https://github.com/ppy/osu/releases/latest/download/osu.AppImage) | [iOS 10+](https://osu.ppy.sh/home/testflight) | [Android 5+](https://github.com/ppy/osu/releases/latest/download/sh.ppy.osulazer.apk) | ------------- | ------------- | ------------- | ------------- | ------------- | - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. From 34a8607b20b6e95eeaaa7630d7d17a38f6ca5cae Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Wed, 8 Sep 2021 20:08:25 -0700 Subject: [PATCH 885/961] Remove unnecessary prerequisites for windows 8.1 --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9dd5280d13..786ce2589d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,6 @@ If you are looking to install or test osu! without setting up a development envi - The iOS testflight link may fill up (Apple has a hard limit of 10,000 users). We reset it occasionally when this happens. Please do not ask about this. Check back regularly for link resets or follow [peppy](https://twitter.com/ppy) on twitter for announcements of link resets. -- When running on Windows 8.1, *[additional prerequisites](https://docs.microsoft.com/en-us/dotnet/core/install/windows?tabs=net50&pivots=os-windows#dependencies)** may be required to correctly run .NET 5 applications if your operating system is not up-to-date with the latest service packs. If your platform is not listed above, there is still a chance you can manually build it by following the instructions below. ## Developing a custom ruleset From 9a0dbaa8e34152fefd7a18fe33e111cb8539b26a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 12:39:28 +0900 Subject: [PATCH 886/961] Remove default parameter from build benchmark project configuration --- .../.idea/runConfigurations/Benchmarks.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml index 8fa7608b8e..498a710df9 100644 --- a/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml +++ b/.idea/.idea.osu.Desktop/.idea/runConfigurations/Benchmarks.xml @@ -1,8 +1,8 @@ - \ No newline at end of file From 210640af0924f5e77ccad3633d06f7b898cb86f7 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Sep 2021 12:39:40 +0900 Subject: [PATCH 887/961] Fix overlay not refreshed in `TestSceneBeatmapSetOverlay` --- .../Visual/Online/TestSceneBeatmapSetOverlay.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index de7e4075f3..40c8fae50a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -11,6 +11,7 @@ using osu.Game.Users; using System; using System.Collections.Generic; using System.Linq; +using osu.Framework.Utils; namespace osu.Game.Tests.Visual.Online { @@ -240,7 +241,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("show explicit map", () => { - var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + var beatmapSet = getBeatmapSet(); beatmapSet.OnlineInfo.HasExplicitContent = true; overlay.ShowBeatmapSet(beatmapSet); }); @@ -251,7 +252,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("show featured map", () => { - var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + var beatmapSet = getBeatmapSet(); beatmapSet.OnlineInfo.TrackId = 1; overlay.ShowBeatmapSet(beatmapSet); }); @@ -319,6 +320,14 @@ namespace osu.Game.Tests.Visual.Online }; } + private BeatmapSetInfo getBeatmapSet() + { + var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; + // Overlay doesn't reload if the same beatmap set is set. + beatmapSet.OnlineBeatmapSetID = RNG.Next(); + return beatmapSet; + } + private void downloadAssert(bool shown) { AddAssert($"is download button {(shown ? "shown" : "hidden")}", () => overlay.Header.HeaderContent.DownloadButtonsVisible == shown); From 45a534a1ba0f1c836215c5a4b1578da733c50fdf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 12:39:45 +0900 Subject: [PATCH 888/961] Fix duplicated `GlobalSetup` attribute on `BenchmarkMod` --- osu.Game.Benchmarks/BenchmarkMod.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkMod.cs b/osu.Game.Benchmarks/BenchmarkMod.cs index 050ddf36d5..c5375e9f09 100644 --- a/osu.Game.Benchmarks/BenchmarkMod.cs +++ b/osu.Game.Benchmarks/BenchmarkMod.cs @@ -14,9 +14,9 @@ namespace osu.Game.Benchmarks [Params(1, 10, 100)] public int Times { get; set; } - [GlobalSetup] - public void GlobalSetup() + public override void SetUp() { + base.SetUp(); mod = new OsuModDoubleTime(); } From 278584de99e416aed21ef3034a88d072d61de2c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 12:40:05 +0900 Subject: [PATCH 889/961] Disable optimisations validator (in line with framework project) --- osu.Game.Benchmarks/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Benchmarks/Program.cs b/osu.Game.Benchmarks/Program.cs index c55075fea6..439ced53ab 100644 --- a/osu.Game.Benchmarks/Program.cs +++ b/osu.Game.Benchmarks/Program.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 BenchmarkDotNet.Configs; using BenchmarkDotNet.Running; namespace osu.Game.Benchmarks @@ -11,7 +12,7 @@ namespace osu.Game.Benchmarks { BenchmarkSwitcher .FromAssembly(typeof(Program).Assembly) - .Run(args); + .Run(args, DefaultConfig.Instance.WithOption(ConfigOptions.DisableOptimizationsValidator, true)); } } } From 52bb02baed7538157654dd7e9b470842862c6e70 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Sep 2021 12:51:21 +0900 Subject: [PATCH 890/961] Prefer composite over inheritance for drawable parts --- .../BeatmapSet/BeatmapSetBadgePill.cs | 32 ------------- .../BeatmapSetBadgePillContainer.cs | 45 +++++++++++++++++++ .../BeatmapSet/ExplicitContentBeatmapPill.cs | 22 ++++----- .../BeatmapSet/FeaturedArtistBeatmapPill.cs | 22 ++++----- 4 files changed, 69 insertions(+), 52 deletions(-) delete mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs create mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs deleted file mode 100644 index 15c691103a..0000000000 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePill.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osuTK.Graphics; - -namespace osu.Game.Overlays.BeatmapSet -{ - public class BeatmapSetBadgePill : CircularContainer - { - public BeatmapSetBadgePill() - { - AutoSizeAxes = Axes.Both; - Masking = true; - } - - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OsuColour colours, [CanBeNull] OverlayColourProvider colourProvider) - { - Add(new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider?.Background5 ?? colours?.Gray2 ?? Color4.DarkGray, - }); - } - } -} diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs new file mode 100644 index 0000000000..62bbc35a2d --- /dev/null +++ b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.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 JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; +using osuTK.Graphics; + +namespace osu.Game.Overlays.BeatmapSet +{ + public class BeatmapSetBadgePillContainer : CircularContainer + { + protected override Container Content => contentContainer; + + private readonly Box background; + private readonly Container contentContainer; + + public BeatmapSetBadgePillContainer() + { + Masking = true; + AutoSizeAxes = Axes.Both; + InternalChildren = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + }, + contentContainer = new Container + { + AutoSizeAxes = Axes.Both, + Padding = new MarginPadding { Horizontal = 10f, Vertical = 2f }, + } + }; + } + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] OsuColour colours, [CanBeNull] OverlayColourProvider colourProvider) + { + background.Colour = colourProvider?.Background5 ?? colours?.Gray2 ?? Color4.DarkGray; + } + } +} diff --git a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs index 60fa3ea900..4bd3f132f9 100644 --- a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs +++ b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs @@ -1,27 +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.Extensions.LocalisationExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class ExplicitContentBeatmapPill : BeatmapSetBadgePill + public class ExplicitContentBeatmapPill : CompositeDrawable { - [BackgroundDependencyLoader] - private void load() + public ExplicitContentBeatmapPill() { - Add(new OsuSpriteText + AutoSizeAxes = Axes.Both; + InternalChild = new BeatmapSetBadgePillContainer { - Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, - Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), - Colour = OverlayColourProvider.Orange.Colour2, - }); + Child = new OsuSpriteText + { + Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Orange.Colour2, + } + }; } } } diff --git a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs index 7facc2953a..a9950b1b60 100644 --- a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs +++ b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs @@ -1,27 +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.Extensions.LocalisationExtensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; namespace osu.Game.Overlays.BeatmapSet { - public class FeaturedArtistBeatmapPill : BeatmapSetBadgePill + public class FeaturedArtistBeatmapPill : CompositeDrawable { - [BackgroundDependencyLoader] - private void load() + public FeaturedArtistBeatmapPill() { - Add(new OsuSpriteText + AutoSizeAxes = Axes.Both; + InternalChild = new BeatmapSetBadgePillContainer { - Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, - Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(), - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), - Colour = OverlayColourProvider.Blue.Colour1 - }); + Child = new OsuSpriteText + { + Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Blue.Colour1 + } + }; } } } From 41a2e6eeeba92bfd9e0b1d8e896f6c283d3d6e1c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 14:56:39 +0900 Subject: [PATCH 891/961] Fix cache not actually caching anything --- osu.Game/Configuration/SettingSourceAttribute.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/SettingSourceAttribute.cs b/osu.Game/Configuration/SettingSourceAttribute.cs index 4346a583ec..5db502804d 100644 --- a/osu.Game/Configuration/SettingSourceAttribute.cs +++ b/osu.Game/Configuration/SettingSourceAttribute.cs @@ -168,14 +168,14 @@ namespace osu.Game.Configuration } } - private static readonly ConcurrentDictionary> property_info_cache = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary property_info_cache = new ConcurrentDictionary(); public static IEnumerable<(SettingSourceAttribute, PropertyInfo)> GetSettingsSourceProperties(this object obj) { var type = obj.GetType(); if (!property_info_cache.TryGetValue(type, out var properties)) - property_info_cache[type] = properties = getSettingsSourceProperties(type); + property_info_cache[type] = properties = getSettingsSourceProperties(type).ToArray(); return properties; } From efaf07dbc8db673737ab14d80f37f8e0fcf18f82 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 14:47:19 +0900 Subject: [PATCH 892/961] Add benchmark coverage of mod retrieval --- osu.Game.Benchmarks/BenchmarkRuleset.cs | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 osu.Game.Benchmarks/BenchmarkRuleset.cs diff --git a/osu.Game.Benchmarks/BenchmarkRuleset.cs b/osu.Game.Benchmarks/BenchmarkRuleset.cs new file mode 100644 index 0000000000..1b315b5001 --- /dev/null +++ b/osu.Game.Benchmarks/BenchmarkRuleset.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 BenchmarkDotNet.Attributes; +using osu.Game.Online.API; +using osu.Game.Rulesets.Osu; + +namespace osu.Game.Benchmarks +{ + public class BenchmarkRuleset : BenchmarkTest + { + private OsuRuleset ruleset; + private APIMod apiModDoubleTime; + private APIMod apiModDifficultyAdjust; + + public override void SetUp() + { + base.SetUp(); + ruleset = new OsuRuleset(); + apiModDoubleTime = new APIMod { Acronym = "DT" }; + apiModDifficultyAdjust = new APIMod { Acronym = "DA" }; + } + + [Benchmark] + public void BenchmarkToModDoubleTime() + { + apiModDoubleTime.ToMod(ruleset); + } + + [Benchmark] + public void BenchmarkToModDifficultyAdjust() + { + apiModDifficultyAdjust.ToMod(ruleset); + } + + [Benchmark] + public void BenchmarkGetAllMods() + { + ruleset.GetAllMods(); + } + } +} From 4708cb7317f21287ab7448d9209d6c7eedf4681a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 15:15:18 +0900 Subject: [PATCH 893/961] Fix enumerable not being consumed --- osu.Game.Benchmarks/BenchmarkRuleset.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Benchmarks/BenchmarkRuleset.cs b/osu.Game.Benchmarks/BenchmarkRuleset.cs index 1b315b5001..63c99dcb2b 100644 --- a/osu.Game.Benchmarks/BenchmarkRuleset.cs +++ b/osu.Game.Benchmarks/BenchmarkRuleset.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Engines; using osu.Game.Online.API; using osu.Game.Rulesets.Osu; @@ -36,7 +37,7 @@ namespace osu.Game.Benchmarks [Benchmark] public void BenchmarkGetAllMods() { - ruleset.GetAllMods(); + ruleset.GetAllMods().Consume(new Consumer()); } } } From b01cf5c937bad88ffea9ad1df75bf9f0dfb813dd Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Thu, 9 Sep 2021 15:33:47 +0900 Subject: [PATCH 894/961] Don't play hover/select sounds for UpdatableAvatar unless it's interactable --- osu.Game/Users/Drawables/UpdateableAvatar.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index df724404e9..a8726d0cab 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -69,14 +69,20 @@ namespace osu.Game.Users.Drawables if (user == null && !showGuestOnNull) return null; - var avatar = new ClickableAvatar(user) + if (!openOnClick) + { + return new DrawableAvatar(user) + { + RelativeSizeAxes = Axes.Both, + }; + } + + return new ClickableAvatar(user) { OpenOnClick = openOnClick, ShowUsernameTooltip = showUsernameTooltip, RelativeSizeAxes = Axes.Both, }; - - return avatar; } } } From e66d76d26e2979cd5a858aa2aa2b0061c36856ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 15:43:55 +0900 Subject: [PATCH 895/961] Avoid settings copy if there are no settings --- osu.Game/Online/API/APIMod.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 4427c82a8b..596d567480 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -53,12 +53,15 @@ namespace osu.Game.Online.API if (resultMod == null) throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}."); - foreach (var (_, property) in resultMod.GetSettingsSourceProperties()) + if (Settings.Count > 0) { - if (!Settings.TryGetValue(property.Name.Underscore(), out object settingValue)) - continue; + foreach (var (_, property) in resultMod.GetSettingsSourceProperties()) + { + if (!Settings.TryGetValue(property.Name.Underscore(), out object settingValue)) + continue; - resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue); + resultMod.CopyAdjustedSetting((IBindable)property.GetValue(resultMod), settingValue); + } } return resultMod; From 4d0530ca9d1b2d110fc407bac3cc112161367bfb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 16:34:49 +0900 Subject: [PATCH 896/961] Add new methods to ruleset for quicker mod lookups --- osu.Game.Benchmarks/BenchmarkRuleset.cs | 6 +++ .../Components/TournamentModIcon.cs | 2 +- osu.Game/Online/API/APIMod.cs | 2 +- .../Requests/Responses/APILegacyScoreInfo.cs | 2 +- .../BeatmapSet/LeaderboardModSelector.cs | 2 +- .../IncompatibilityDisplayingModButton.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 40 +++++++++++++++++++ 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkRuleset.cs b/osu.Game.Benchmarks/BenchmarkRuleset.cs index 63c99dcb2b..f3d678a2b0 100644 --- a/osu.Game.Benchmarks/BenchmarkRuleset.cs +++ b/osu.Game.Benchmarks/BenchmarkRuleset.cs @@ -39,5 +39,11 @@ namespace osu.Game.Benchmarks { ruleset.GetAllMods().Consume(new Consumer()); } + + [Benchmark] + public void BenchmarkGetAllModsForReference() + { + ruleset.GetAllModsForReference().Consume(new Consumer()); + } } } diff --git a/osu.Game.Tournament/Components/TournamentModIcon.cs b/osu.Game.Tournament/Components/TournamentModIcon.cs index 43ac92d285..709e99b165 100644 --- a/osu.Game.Tournament/Components/TournamentModIcon.cs +++ b/osu.Game.Tournament/Components/TournamentModIcon.cs @@ -49,7 +49,7 @@ namespace osu.Game.Tournament.Components } var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0); - var modIcon = ruleset?.CreateInstance().GetAllMods().FirstOrDefault(mod => mod.Acronym == modAcronym); + var modIcon = ruleset?.CreateInstance().GetModForAcronym(modAcronym); if (modIcon == null) return; diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 596d567480..f31f8bc92a 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.API public Mod ToMod(Ruleset ruleset) { - Mod resultMod = ruleset.GetAllMods().FirstOrDefault(m => m.Acronym == Acronym); + Mod resultMod = ruleset.GetModForAcronym(Acronym); if (resultMod == null) throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}."); diff --git a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs index 1b394185fd..e74db7de6e 100644 --- a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs @@ -23,7 +23,7 @@ namespace osu.Game.Online.API.Requests.Responses var rulesetInstance = ruleset.CreateInstance(); - var mods = Mods != null ? rulesetInstance.GetAllMods().Where(mod => Mods.Contains(mod.Acronym)).ToArray() : Array.Empty(); + var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.GetModForAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty(); // all API scores provided by this class are considered to be legacy. mods = mods.Append(rulesetInstance.GetAllMods().OfType().Single()).ToArray(); diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs index 5b903372fd..517da11c8c 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet return; modsContainer.Add(new ModButton(new ModNoMod())); - modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllMods().Where(m => m.UserPlayable).Select(m => new ModButton(m))); + modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllModsForReference().Where(m => m.UserPlayable).Select(m => new ModButton(m))); modsContainer.ForEach(button => { diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs index c8e44ee159..8d0746f24d 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs @@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Mods var incompatibleTypes = mod.IncompatibleMods; - var allMods = ruleset.Value.CreateInstance().GetAllMods(); + var allMods = ruleset.Value.CreateInstance().GetAllModsForReference(); incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods"; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index de62cf8d33..2f65bd76a4 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using osu.Framework.Graphics; @@ -23,6 +24,7 @@ using osu.Game.Scoring; using osu.Game.Skinning; using osu.Game.Users; using JetBrains.Annotations; +using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Testing; @@ -38,6 +40,13 @@ namespace osu.Game.Rulesets { public RulesetInfo RulesetInfo { get; internal set; } + /// + /// Returns fresh instances of all mods. + /// + /// + /// This comes with considerable allocation overhead. If only accessing for reference purposes (ie. not changing bindables / settings) + /// use instead. + /// public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast() // Confine all mods of each mod type into a single IEnumerable .SelectMany(GetModsFor) @@ -46,6 +55,37 @@ namespace osu.Game.Rulesets // Resolve MultiMods as their .Mods property .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); + private static readonly ConcurrentDictionary mod_reference_cache = new ConcurrentDictionary(); + + /// + /// Returns all mods for a query-only purpose. + /// Bindables should not be considered usable when retrieving via this method (use instead). + /// + public IEnumerable GetAllModsForReference() + { + if (!(RulesetInfo.ID is int id)) + return GetAllMods(); + + if (!mod_reference_cache.TryGetValue(id, out var mods)) + mod_reference_cache[id] = mods = GetAllMods().ToArray(); + + return mods; + } + + /// + /// Returns a fresh instance of the mod matching the specified acronym. + /// + /// The acronym to query for . + public Mod GetModForAcronym(string acronym) + { + var type = GetAllModsForReference().FirstOrDefault(m => m.Acronym == acronym)?.GetType(); + + if (type != null) + return (Mod)Activator.CreateInstance(type); + + return null; + } + public abstract IEnumerable GetModsFor(ModType type); /// From 2edb8510081ee30e14f3c9feec7451319acd9e0a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 16:46:24 +0900 Subject: [PATCH 897/961] Add ability to lookup mod from a type specification --- osu.Game.Benchmarks/BenchmarkRuleset.cs | 13 +++++++++++++ .../Components/TournamentModIcon.cs | 1 - .../Requests/Responses/APILegacyScoreInfo.cs | 2 +- osu.Game/OsuGameBase.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 17 +++++++++++++++-- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- osu.Game/Tests/Visual/PlayerTestScene.cs | 2 +- 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkRuleset.cs b/osu.Game.Benchmarks/BenchmarkRuleset.cs index f3d678a2b0..aa59cb7fa3 100644 --- a/osu.Game.Benchmarks/BenchmarkRuleset.cs +++ b/osu.Game.Benchmarks/BenchmarkRuleset.cs @@ -4,6 +4,7 @@ using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Engines; using osu.Game.Online.API; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; namespace osu.Game.Benchmarks @@ -45,5 +46,17 @@ namespace osu.Game.Benchmarks { ruleset.GetAllModsForReference().Consume(new Consumer()); } + + [Benchmark] + public void BenchmarkGetForAcronym() + { + ruleset.GetModForAcronym("DT"); + } + + [Benchmark] + public void BenchmarkGetForType() + { + ruleset.GetMod(); + } } } diff --git a/osu.Game.Tournament/Components/TournamentModIcon.cs b/osu.Game.Tournament/Components/TournamentModIcon.cs index 709e99b165..b8486b5b2d 100644 --- a/osu.Game.Tournament/Components/TournamentModIcon.cs +++ b/osu.Game.Tournament/Components/TournamentModIcon.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.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; diff --git a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs index e74db7de6e..d1c6f0a55a 100644 --- a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs @@ -26,7 +26,7 @@ namespace osu.Game.Online.API.Requests.Responses var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.GetModForAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty(); // all API scores provided by this class are considered to be legacy. - mods = mods.Append(rulesetInstance.GetAllMods().OfType().Single()).ToArray(); + mods = mods.Append(rulesetInstance.GetMod()).ToArray(); var scoreInfo = new ScoreInfo { diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index f4db0f2603..d52a07266c 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -166,7 +166,7 @@ namespace osu.Game public OsuGameBase() { - UseDevelopmentServer = DebugUtils.IsDebugBuild; + UseDevelopmentServer = false; Name = @"osu!"; } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 2f65bd76a4..34e4606133 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -24,7 +24,6 @@ using osu.Game.Scoring; using osu.Game.Skinning; using osu.Game.Users; using JetBrains.Annotations; -using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.EnumExtensions; using osu.Framework.Testing; @@ -86,6 +85,20 @@ namespace osu.Game.Rulesets return null; } + /// + /// Returns a fresh instance of the mod matching the specified type. + /// + public T GetMod() + where T : Mod + { + var type = GetAllModsForReference().FirstOrDefault(m => m is T)?.GetType(); + + if (type != null) + return (T)Activator.CreateInstance(type); + + return null; + } + public abstract IEnumerable GetModsFor(ModType type); /// @@ -166,7 +179,7 @@ namespace osu.Game.Rulesets } [CanBeNull] - public ModAutoplay GetAutoplayMod() => GetAllMods().OfType().FirstOrDefault(); + public ModAutoplay GetAutoplayMod() => GetMod(); public virtual ISkin CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null; diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 2f17167297..010f33e3ed 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -67,7 +67,7 @@ namespace osu.Game.Scoring.Legacy // lazer replays get a really high version number. if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION) - scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.GetAllMods().OfType().Single()).ToArray(); + scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.GetMod()).ToArray(); currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods); scoreInfo.Beatmap = currentBeatmap.BeatmapInfo; diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index 93491c800f..a31a6433ea 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual if (!AllowFail) { - var noFailMod = ruleset.GetAllMods().FirstOrDefault(m => m is ModNoFail); + var noFailMod = ruleset.GetMod(); if (noFailMod != null) SelectedMods.Value = new[] { noFailMod }; } From 9b34ffc3029e20027f32ac866587853d60d76eeb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 17:12:38 +0900 Subject: [PATCH 898/961] Undo big oopsie --- osu.Game/OsuGameBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index d52a07266c..f4db0f2603 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -166,7 +166,7 @@ namespace osu.Game public OsuGameBase() { - UseDevelopmentServer = false; + UseDevelopmentServer = DebugUtils.IsDebugBuild; Name = @"osu!"; } From 29f947fa07ac5a550f8470a0b178117021144d9a Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Sep 2021 19:25:30 +0900 Subject: [PATCH 899/961] Revert `ExplicitContentBeatmapPill`, don't try to reuse common code --- .../BeatmapSetBadgePillContainer.cs | 45 ------------------- .../BeatmapSet/ExplicitContentBeatmapPill.cs | 28 +++++++++--- .../BeatmapSet/FeaturedArtistBeatmapPill.cs | 28 +++++++++--- 3 files changed, 46 insertions(+), 55 deletions(-) delete mode 100644 osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs b/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs deleted file mode 100644 index 62bbc35a2d..0000000000 --- a/osu.Game/Overlays/BeatmapSet/BeatmapSetBadgePillContainer.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using JetBrains.Annotations; -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Shapes; -using osu.Game.Graphics; -using osuTK.Graphics; - -namespace osu.Game.Overlays.BeatmapSet -{ - public class BeatmapSetBadgePillContainer : CircularContainer - { - protected override Container Content => contentContainer; - - private readonly Box background; - private readonly Container contentContainer; - - public BeatmapSetBadgePillContainer() - { - Masking = true; - AutoSizeAxes = Axes.Both; - InternalChildren = new Drawable[] - { - background = new Box - { - RelativeSizeAxes = Axes.Both, - }, - contentContainer = new Container - { - AutoSizeAxes = Axes.Both, - Padding = new MarginPadding { Horizontal = 10f, Vertical = 2f }, - } - }; - } - - [BackgroundDependencyLoader(true)] - private void load([CanBeNull] OsuColour colours, [CanBeNull] OverlayColourProvider colourProvider) - { - background.Colour = colourProvider?.Background5 ?? colours?.Gray2 ?? Color4.DarkGray; - } - } -} diff --git a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs index 4bd3f132f9..ba78592ed2 100644 --- a/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs +++ b/osu.Game/Overlays/BeatmapSet/ExplicitContentBeatmapPill.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Extensions.LocalisationExtensions; 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.Resources.Localisation.Web; @@ -15,13 +17,29 @@ namespace osu.Game.Overlays.BeatmapSet public ExplicitContentBeatmapPill() { AutoSizeAxes = Axes.Both; - InternalChild = new BeatmapSetBadgePillContainer + } + + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, OverlayColourProvider colourProvider) + { + InternalChild = new CircularContainer { - Child = new OsuSpriteText + Masking = true, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), - Colour = OverlayColourProvider.Orange.Colour2, + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider?.Background5 ?? colours.Gray2, + }, + new OsuSpriteText + { + Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, + Text = BeatmapsetsStrings.NsfwBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Orange.Colour2, + } } }; } diff --git a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs index a9950b1b60..fdee0799ff 100644 --- a/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs +++ b/osu.Game/Overlays/BeatmapSet/FeaturedArtistBeatmapPill.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Extensions.LocalisationExtensions; 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.Resources.Localisation.Web; @@ -15,13 +17,29 @@ namespace osu.Game.Overlays.BeatmapSet public FeaturedArtistBeatmapPill() { AutoSizeAxes = Axes.Both; - InternalChild = new BeatmapSetBadgePillContainer + } + + [BackgroundDependencyLoader(true)] + private void load(OsuColour colours, OverlayColourProvider colourProvider) + { + InternalChild = new CircularContainer { - Child = new OsuSpriteText + Masking = true, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] { - Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(), - Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), - Colour = OverlayColourProvider.Blue.Colour1 + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = colourProvider?.Background5 ?? colours.Gray2, + }, + new OsuSpriteText + { + Margin = new MarginPadding { Horizontal = 10f, Vertical = 2f }, + Text = BeatmapsetsStrings.FeaturedArtistBadgeLabel.ToUpper(), + Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold), + Colour = OverlayColourProvider.Blue.Colour1, + } } }; } From a2c2646230bd6d92e057238d9c7298fa2f291220 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Thu, 9 Sep 2021 19:36:47 +0900 Subject: [PATCH 900/961] Use a counter instead of RNG --- osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs index 40c8fae50a..f420ad976b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs @@ -11,7 +11,6 @@ using osu.Game.Users; using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Utils; namespace osu.Game.Tests.Visual.Online { @@ -22,6 +21,8 @@ namespace osu.Game.Tests.Visual.Online protected override bool UseOnlineAPI => true; + private int nextBeatmapSetId = 1; + public TestSceneBeatmapSetOverlay() { Add(overlay = new TestBeatmapSetOverlay()); @@ -323,8 +324,8 @@ namespace osu.Game.Tests.Visual.Online private BeatmapSetInfo getBeatmapSet() { var beatmapSet = CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet; - // Overlay doesn't reload if the same beatmap set is set. - beatmapSet.OnlineBeatmapSetID = RNG.Next(); + // Make sure the overlay is reloaded (see `BeatmapSetInfo.Equals`). + beatmapSet.OnlineBeatmapSetID = nextBeatmapSetId++; return beatmapSet; } From 99b6f0352cf05f733e374a1889a3c416a1b42332 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 22:04:00 +0900 Subject: [PATCH 901/961] Always start decoupled clock regardless of track source --- osu.Game/Screens/Menu/IntroTriangles.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 69333d4a12..36296487a8 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -90,8 +90,7 @@ namespace osu.Game.Screens.Menu protected override void StartTrack() { - if (UsingThemedIntro) - decoupledClock.Start(); + decoupledClock.Start(); } private class TrianglesIntroSequence : CompositeDrawable From 6c18df24ec432d848ba8c6b3b6e8d44691b48aad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 9 Sep 2021 22:04:16 +0900 Subject: [PATCH 902/961] Change how `UsingThemedIntro` is set to improve clarity --- osu.Game/Screens/Menu/IntroScreen.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Menu/IntroScreen.cs b/osu.Game/Screens/Menu/IntroScreen.cs index ac4a53f4a9..cfe14eab92 100644 --- a/osu.Game/Screens/Menu/IntroScreen.cs +++ b/osu.Game/Screens/Menu/IntroScreen.cs @@ -115,7 +115,9 @@ namespace osu.Game.Screens.Menu if (setInfo == null) return false; - return (initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0])) != null; + initialBeatmap = beatmaps.GetWorkingBeatmap(setInfo.Beatmaps[0]); + + return UsingThemedIntro = initialBeatmap != null; } } @@ -184,7 +186,6 @@ namespace osu.Game.Screens.Menu { beatmap.Value = initialBeatmap; Track = initialBeatmap.Track; - UsingThemedIntro = !initialBeatmap.Track.IsDummyDevice; // ensure the track starts at maximum volume musicController.CurrentTrack.FinishTransforms(); From 2e00c7184206c190fedce24245dc0b852ecfb52e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 01:57:33 +0900 Subject: [PATCH 903/961] Add failing test coverage --- .../Online/TestSceneBeatmapListingOverlay.cs | 90 +++++++++++++++---- 1 file changed, 72 insertions(+), 18 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index 5bfb676f81..abadfac76a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -5,10 +5,10 @@ using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -17,10 +17,11 @@ using osu.Game.Overlays.BeatmapListing; using osu.Game.Rulesets; using osu.Game.Scoring; using osu.Game.Users; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneBeatmapListingOverlay : OsuTestScene + public class TestSceneBeatmapListingOverlay : OsuManualInputManagerTestScene { private readonly List setsForResponse = new List(); @@ -28,27 +29,33 @@ namespace osu.Game.Tests.Visual.Online private BeatmapListingSearchControl searchControl => overlay.ChildrenOfType().Single(); - [BackgroundDependencyLoader] - private void load() + [SetUpSteps] + public void SetUpSteps() { - Child = overlay = new BeatmapListingOverlay { State = { Value = Visibility.Visible } }; - - ((DummyAPIAccess)API).HandleRequest = req => + AddStep("setup overlay", () => { - if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false; - - searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse - { - BeatmapSets = setsForResponse, - }); - - return true; - }; + Child = overlay = new BeatmapListingOverlay { State = { Value = Visibility.Visible } }; + setsForResponse.Clear(); + }); AddStep("initialize dummy", () => { + var api = (DummyAPIAccess)API; + + api.HandleRequest = req => + { + if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false; + + searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse + { + BeatmapSets = setsForResponse, + }); + + return true; + }; + // non-supporter user - ((DummyAPIAccess)API).LocalUser.Value = new User + api.LocalUser.Value = new User { Username = "TestBot", Id = API.LocalUser.Value.Id + 1, @@ -56,6 +63,51 @@ namespace osu.Game.Tests.Visual.Online }); } + [Test] + public void TestHideViaBack() + { + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + AddStep("hide", () => InputManager.Key(Key.Escape)); + AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden); + } + + [Test] + public void TestHideViaBackWithSearch() + { + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + + AddStep("search something", () => overlay.ChildrenOfType().First().Text = "search"); + + AddStep("kill search", () => InputManager.Key(Key.Escape)); + + AddAssert("search textbox empty", () => string.IsNullOrEmpty(overlay.ChildrenOfType().First().Text)); + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + + AddStep("hide", () => InputManager.Key(Key.Escape)); + AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden); + } + + [Test] + public void TestHideViaBackWithScrolledSearch() + { + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + + AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet, 100).ToArray())); + + AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any()); + + AddStep("scroll to bottom", () => overlay.ChildrenOfType().First().ScrollToEnd()); + + AddStep("kill search", () => InputManager.Key(Key.Escape)); + + AddUntilStep("search textbox empty", () => string.IsNullOrEmpty(overlay.ChildrenOfType().First().Text)); + AddUntilStep("is scrolled to top", () => overlay.ChildrenOfType().First().Current == 0); + AddAssert("is visible", () => overlay.State.Value == Visibility.Visible); + + AddStep("hide", () => InputManager.Key(Key.Escape)); + AddUntilStep("is hidden", () => overlay.State.Value == Visibility.Hidden); + } + [Test] public void TestNoBeatmapsPlaceholder() { @@ -193,13 +245,15 @@ namespace osu.Game.Tests.Visual.Online noPlaceholderShown(); } + private static int searchCount; + private void fetchFor(params BeatmapSetInfo[] beatmaps) { setsForResponse.Clear(); setsForResponse.AddRange(beatmaps.Select(b => new TestAPIBeatmapSet(b))); // trigger arbitrary change for fetching. - searchControl.Query.TriggerChange(); + searchControl.Query.Value = $"search {searchCount++}"; } private void setRankAchievedFilter(ScoreRank[] ranks) From c101d1f20570829380b9952d0dd99999118eb3bf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 01:57:55 +0900 Subject: [PATCH 904/961] Fix beatmap listing overlay not hiding via keyboard control when scrolled Closes https://github.com/ppy/osu/issues/14684. --- .../Graphics/UserInterface/FocusedTextBox.cs | 2 +- .../BeatmapListingSearchControl.cs | 24 +++++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs index ed9f0710b0..6c8238a1b8 100644 --- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs +++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs @@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterface return base.OnKeyDown(e); } - public bool OnPressed(GlobalAction action) + public virtual bool OnPressed(GlobalAction action) { if (!HasFocus) return false; diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index d1e2ac38df..07a0cfb57f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -3,21 +3,22 @@ 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 osuTK; -using osu.Framework.Bindables; using osu.Framework.Input.Events; -using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps; +using osu.Game.Beatmaps.Drawables; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osu.Game.Resources.Localisation.Web; -using osuTK.Graphics; using osu.Game.Rulesets; using osu.Game.Scoring; +using osuTK; +using osuTK.Graphics; namespace osu.Game.Overlays.BeatmapListing { @@ -117,7 +118,7 @@ namespace osu.Game.Overlays.BeatmapListing textBox = new BeatmapSearchTextBox { RelativeSizeAxes = Axes.X, - TypingStarted = () => TypingStarted?.Invoke(), + TextChanged = () => TypingStarted?.Invoke(), }, new ReverseChildIDFillFlowContainer { @@ -167,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapListing /// /// Any time the text box receives key events (even while masked). /// - public Action TypingStarted; + public Action TextChanged; protected override Color4 SelectionColour => Color4.Gray; @@ -181,7 +182,16 @@ namespace osu.Game.Overlays.BeatmapListing if (!base.OnKeyDown(e)) return false; - TypingStarted?.Invoke(); + TextChanged?.Invoke(); + return true; + } + + public override bool OnPressed(GlobalAction action) + { + if (!base.OnPressed(action)) + return false; + + TextChanged?.Invoke(); return true; } } From 3865988e48d1ef98ddcaceb947518af7eaa8f0b6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 02:15:13 +0900 Subject: [PATCH 905/961] Add test coverage for back button support in password popover --- .../TestSceneMultiplayerLoungeSubScreen.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs index 99f6ab1ae1..61565c88f4 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerLoungeSubScreen.cs @@ -51,6 +51,24 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("room join password correct", () => lastJoinedPassword == null); } + [Test] + public void TestPopoverHidesOnBackButton() + { + AddStep("add room", () => RoomManager.AddRooms(1, withPassword: true)); + AddStep("select room", () => InputManager.Key(Key.Down)); + AddStep("attempt join room", () => InputManager.Key(Key.Enter)); + + AddUntilStep("password prompt appeared", () => InputManager.ChildrenOfType().Any()); + + AddAssert("textbox has focus", () => InputManager.FocusedDrawable is OsuPasswordTextBox); + + AddStep("hit escape", () => InputManager.Key(Key.Escape)); + AddAssert("textbox lost focus", () => InputManager.FocusedDrawable is SearchTextBox); + + AddStep("hit escape", () => InputManager.Key(Key.Escape)); + AddUntilStep("password prompt hidden", () => !InputManager.ChildrenOfType().Any()); + } + [Test] public void TestPopoverHidesOnLeavingScreen() { From 344bf2ab7c1038d4b8e64e7645f03bc93085713a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 02:15:30 +0900 Subject: [PATCH 906/961] Allow popovers to be closed via back button press Closes https://github.com/ppy/osu/issues/14669. --- .../Graphics/UserInterfaceV2/OsuPopover.cs | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index c07a5de1e4..fac0661a15 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -4,14 +4,17 @@ using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input.Bindings; +using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; namespace osu.Game.Graphics.UserInterfaceV2 { - public class OsuPopover : Popover + public class OsuPopover : Popover, IKeyBindingHandler { private const float fade_duration = 250; private const double scale_duration = 500; @@ -51,5 +54,24 @@ namespace osu.Game.Graphics.UserInterfaceV2 this.ScaleTo(0.7f, scale_duration, Easing.OutQuint); this.FadeOut(fade_duration, Easing.OutQuint); } + + public bool OnPressed(GlobalAction action) + { + if (State.Value == Visibility.Hidden) + return false; + + if (action == GlobalAction.Back) + { + Hide(); + return true; + } + + return false; + } + + public void OnReleased(GlobalAction action) + { + throw new System.NotImplementedException(); + } } } From 32de13cb96f4dd48d8f66980e97af28fdd9eac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 9 Sep 2021 21:33:02 +0200 Subject: [PATCH 907/961] Use consistent assertions for checking placeholder presence --- .../Visual/Online/TestSceneBeatmapListingOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs index abadfac76a..963809ebe1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapListingOverlay.cs @@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("show many results", () => fetchFor(Enumerable.Repeat(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet, 100).ToArray())); - AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any()); + AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any(d => d.IsPresent)); AddStep("scroll to bottom", () => overlay.ChildrenOfType().First().ScrollToEnd()); @@ -115,7 +115,7 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("placeholder shown", () => overlay.ChildrenOfType().SingleOrDefault()?.IsPresent == true); AddStep("fetch for 1 beatmap", () => fetchFor(CreateBeatmap(Ruleset.Value).BeatmapInfo.BeatmapSet)); - AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any()); + AddUntilStep("placeholder hidden", () => !overlay.ChildrenOfType().Any(d => d.IsPresent)); AddStep("fetch for 0 beatmaps", () => fetchFor()); AddUntilStep("placeholder shown", () => overlay.ChildrenOfType().SingleOrDefault()?.IsPresent == true); @@ -283,8 +283,8 @@ namespace osu.Game.Tests.Visual.Online private void noPlaceholderShown() { AddUntilStep("no placeholder shown", () => - !overlay.ChildrenOfType().Any() - && !overlay.ChildrenOfType().Any()); + !overlay.ChildrenOfType().Any(d => d.IsPresent) + && !overlay.ChildrenOfType().Any(d => d.IsPresent)); } private class TestAPIBeatmapSet : APIBeatmapSet From ce6b022a9042d56f59c1c7fc8eae19377598bc87 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 10:59:30 +0900 Subject: [PATCH 908/961] Remove unused `IMod` specification from `APIMod` --- osu.Game/Online/API/APIMod.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index f31f8bc92a..5514ce5e40 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -16,7 +16,7 @@ using osu.Game.Utils; namespace osu.Game.Online.API { [MessagePackObject] - public class APIMod : IMod, IEquatable + public class APIMod { [JsonProperty("acronym")] [Key(0)] @@ -67,8 +67,6 @@ namespace osu.Game.Online.API return resultMod; } - public bool Equals(IMod other) => other is APIMod them && Equals(them); - public bool Equals(APIMod other) { if (ReferenceEquals(null, other)) return false; From cf633973a91dc977c0dec6d8cf2f020b1dbc3807 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 11:09:13 +0900 Subject: [PATCH 909/961] Refactor exposed mod retrieval methods for better safety --- osu.Game.Benchmarks/BenchmarkRuleset.cs | 8 +-- .../Gameplay/TestSceneAllRulesetPlayers.cs | 2 +- .../SongSelect/TestSceneAdvancedStats.cs | 8 +-- .../TestSceneBeatmapMetadataDisplay.cs | 2 +- .../UserInterface/TestSceneModFlowDisplay.cs | 2 +- .../TestSceneModSelectOverlay.cs | 4 +- .../TestSceneTournamentModDisplay.cs | 2 +- .../Components/TournamentModIcon.cs | 2 +- osu.Game/Online/API/APIMod.cs | 2 +- .../Requests/Responses/APILegacyScoreInfo.cs | 4 +- .../BeatmapSet/LeaderboardModSelector.cs | 2 +- .../IncompatibilityDisplayingModButton.cs | 4 +- osu.Game/Rulesets/Mods/IMod.cs | 19 +++++- osu.Game/Rulesets/Mods/Mod.cs | 7 --- osu.Game/Rulesets/Ruleset.cs | 63 ++++++++++--------- osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs | 2 +- .../Tests/Beatmaps/LegacyModConversionTest.cs | 2 +- osu.Game/Tests/TestScoreInfo.cs | 2 +- osu.Game/Tests/Visual/PlayerTestScene.cs | 2 +- 19 files changed, 75 insertions(+), 64 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkRuleset.cs b/osu.Game.Benchmarks/BenchmarkRuleset.cs index aa59cb7fa3..2835ec9499 100644 --- a/osu.Game.Benchmarks/BenchmarkRuleset.cs +++ b/osu.Game.Benchmarks/BenchmarkRuleset.cs @@ -38,25 +38,25 @@ namespace osu.Game.Benchmarks [Benchmark] public void BenchmarkGetAllMods() { - ruleset.GetAllMods().Consume(new Consumer()); + ruleset.CreateAllMods().Consume(new Consumer()); } [Benchmark] public void BenchmarkGetAllModsForReference() { - ruleset.GetAllModsForReference().Consume(new Consumer()); + ruleset.AllMods.Consume(new Consumer()); } [Benchmark] public void BenchmarkGetForAcronym() { - ruleset.GetModForAcronym("DT"); + ruleset.CreateModFromAcronym("DT"); } [Benchmark] public void BenchmarkGetForType() { - ruleset.GetMod(); + ruleset.CreateMod(); } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs index b7dcad3825..8487eecdfa 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs @@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual.Gameplay var working = CreateWorkingBeatmap(rulesetInfo); Beatmap.Value = working; - SelectedMods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) }; + SelectedMods.Value = new[] { ruleset.CreateAllMods().First(m => m is ModNoFail) }; Player = CreatePlayer(ruleset); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 40b2f66d74..5e22bde1d5 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select EZ mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - SelectedMods.Value = new[] { ruleset.GetAllMods().OfType().Single() }; + SelectedMods.Value = new[] { ruleset.CreateAllMods().OfType().Single() }; }); AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue)); @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select HR mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - SelectedMods.Value = new[] { ruleset.GetAllMods().OfType().Single() }; + SelectedMods.Value = new[] { ruleset.CreateAllMods().OfType().Single() }; }); AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue)); @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select unchanged Difficulty Adjust mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single(); + var difficultyAdjustMod = ruleset.CreateAllMods().OfType().Single(); difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty); SelectedMods.Value = new[] { difficultyAdjustMod }; }); @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select changed Difficulty Adjust mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - var difficultyAdjustMod = ruleset.GetAllMods().OfType().Single(); + var difficultyAdjustMod = ruleset.CreateAllMods().OfType().Single(); var originalDifficulty = advancedStats.Beatmap.BaseDifficulty; difficultyAdjustMod.ReadFromDifficulty(originalDifficulty); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs index 66ac700c51..f91d3f595b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapMetadataDisplay.cs @@ -92,7 +92,7 @@ namespace osu.Game.Tests.Visual.SongSelect { AddStep("setup display", () => { - var randomMods = Ruleset.Value.CreateInstance().GetAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList(); + var randomMods = Ruleset.Value.CreateInstance().CreateAllMods().OrderBy(_ => RNG.Next()).Take(5).ToList(); OsuLogo logo = new OsuLogo { Scale = new Vector2(0.15f) }; diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs index 8f057c663b..10eab148de 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModFlowDisplay.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.UserInterface Width = 200, Current = { - Value = new OsuRuleset().GetAllMods().ToArray(), + Value = new OsuRuleset().CreateAllMods().ToArray(), } }; }); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 9e253e089d..28e5644998 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -158,8 +158,8 @@ namespace osu.Game.Tests.Visual.UserInterface var mania = new ManiaRuleset(); testModsWithSameBaseType( - mania.GetAllMods().Single(m => m.GetType() == typeof(ManiaModFadeIn)), - mania.GetAllMods().Single(m => m.GetType() == typeof(ManiaModHidden))); + mania.CreateAllMods().Single(m => m.GetType() == typeof(ManiaModFadeIn)), + mania.CreateAllMods().Single(m => m.GetType() == typeof(ManiaModHidden))); } [Test] diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs index b4d9fa4222..cc1568f429 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Tests.Components private void success(APIBeatmap apiBeatmap) { beatmap = apiBeatmap.ToBeatmap(rulesets); - var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().GetAllMods(); + var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().CreateAllMods(); foreach (var mod in mods) { diff --git a/osu.Game.Tournament/Components/TournamentModIcon.cs b/osu.Game.Tournament/Components/TournamentModIcon.cs index b8486b5b2d..7c4e9c69a2 100644 --- a/osu.Game.Tournament/Components/TournamentModIcon.cs +++ b/osu.Game.Tournament/Components/TournamentModIcon.cs @@ -48,7 +48,7 @@ namespace osu.Game.Tournament.Components } var ruleset = rulesets.GetRuleset(ladderInfo.Ruleset.Value?.ID ?? 0); - var modIcon = ruleset?.CreateInstance().GetModForAcronym(modAcronym); + var modIcon = ruleset?.CreateInstance().CreateModFromAcronym(modAcronym); if (modIcon == null) return; diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 5514ce5e40..5e552dac09 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -48,7 +48,7 @@ namespace osu.Game.Online.API public Mod ToMod(Ruleset ruleset) { - Mod resultMod = ruleset.GetModForAcronym(Acronym); + Mod resultMod = ruleset.CreateModFromAcronym(Acronym); if (resultMod == null) throw new InvalidOperationException($"There is no mod in the ruleset ({ruleset.ShortName}) matching the acronym {Acronym}."); diff --git a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs index d1c6f0a55a..567df524b1 100644 --- a/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs +++ b/osu.Game/Online/API/Requests/Responses/APILegacyScoreInfo.cs @@ -23,10 +23,10 @@ namespace osu.Game.Online.API.Requests.Responses var rulesetInstance = ruleset.CreateInstance(); - var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.GetModForAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty(); + var mods = Mods != null ? Mods.Select(acronym => rulesetInstance.CreateModFromAcronym(acronym)).Where(m => m != null).ToArray() : Array.Empty(); // all API scores provided by this class are considered to be legacy. - mods = mods.Append(rulesetInstance.GetMod()).ToArray(); + mods = mods.Append(rulesetInstance.CreateMod()).ToArray(); var scoreInfo = new ScoreInfo { diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs index 517da11c8c..2683d7bc6d 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet return; modsContainer.Add(new ModButton(new ModNoMod())); - modsContainer.AddRange(ruleset.NewValue.CreateInstance().GetAllModsForReference().Where(m => m.UserPlayable).Select(m => new ModButton(m))); + modsContainer.AddRange(ruleset.NewValue.CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m.CreateInstance()))); modsContainer.ForEach(button => { diff --git a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs index 8d0746f24d..0f51439252 100644 --- a/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs +++ b/osu.Game/Overlays/Mods/IncompatibilityDisplayingModButton.cs @@ -107,9 +107,9 @@ namespace osu.Game.Overlays.Mods var incompatibleTypes = mod.IncompatibleMods; - var allMods = ruleset.Value.CreateInstance().GetAllModsForReference(); + var allMods = ruleset.Value.CreateInstance().AllMods; - incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).ToList(); + incompatibleMods.Value = allMods.Where(m => m.GetType() != mod.GetType() && incompatibleTypes.Any(t => t.IsInstanceOfType(m))).Select(m => m.CreateInstance()).ToList(); incompatibleText.Text = incompatibleMods.Value.Any() ? "Incompatible with:" : "Compatible with all mods"; } } diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs index a5e19f293c..ac17e49e60 100644 --- a/osu.Game/Rulesets/Mods/IMod.cs +++ b/osu.Game/Rulesets/Mods/IMod.cs @@ -2,7 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using Newtonsoft.Json; +using osu.Framework.Graphics.Sprites; namespace osu.Game.Rulesets.Mods { @@ -11,7 +11,22 @@ namespace osu.Game.Rulesets.Mods /// /// The shortened name of this mod. /// - [JsonProperty("acronym")] string Acronym { get; } + + /// + /// The icon of this mod. + /// + IconUsage? Icon { get; } + + /// + /// Whether this mod is playable by an end user. + /// Should be false for cases where the user is not interacting with the game (so it can be excluded from multiplayer selection, for example). + /// + bool UserPlayable { get; } + + /// + /// Create a fresh instance based on this mod. + /// + Mod CreateInstance() => ((Mod)this).DeepClone(); } } diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index 1199d8a956..fedee857c3 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -33,9 +33,6 @@ namespace osu.Game.Rulesets.Mods /// public abstract string Acronym { get; } - /// - /// The icon of this mod. - /// [JsonIgnore] public virtual IconUsage? Icon => null; @@ -106,10 +103,6 @@ namespace osu.Game.Rulesets.Mods [JsonIgnore] public virtual bool HasImplementation => this is IApplicableMod; - /// - /// Whether this mod is playable by an end user. - /// Should be false for cases where the user is not interacting with the game (so it can be excluded from mutliplayer selection, for example). - /// [JsonIgnore] public virtual bool UserPlayable => true; diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 34e4606133..82707ad382 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -39,45 +39,48 @@ namespace osu.Game.Rulesets { public RulesetInfo RulesetInfo { get; internal set; } + private static readonly ConcurrentDictionary mod_reference_cache = new ConcurrentDictionary(); + + /// + /// A queryable source containing all available mods. + /// Call for consumption purposes. + /// + public IEnumerable AllMods + { + get + { + if (!(RulesetInfo.ID is int id)) + return CreateAllMods(); + + if (!mod_reference_cache.TryGetValue(id, out var mods)) + mod_reference_cache[id] = mods = CreateAllMods().Cast().ToArray(); + + return mods; + } + } + /// /// Returns fresh instances of all mods. /// /// /// This comes with considerable allocation overhead. If only accessing for reference purposes (ie. not changing bindables / settings) - /// use instead. + /// use instead. /// - public IEnumerable GetAllMods() => Enum.GetValues(typeof(ModType)).Cast() - // Confine all mods of each mod type into a single IEnumerable - .SelectMany(GetModsFor) - // Filter out all null mods - .Where(mod => mod != null) - // Resolve MultiMods as their .Mods property - .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); - - private static readonly ConcurrentDictionary mod_reference_cache = new ConcurrentDictionary(); - - /// - /// Returns all mods for a query-only purpose. - /// Bindables should not be considered usable when retrieving via this method (use instead). - /// - public IEnumerable GetAllModsForReference() - { - if (!(RulesetInfo.ID is int id)) - return GetAllMods(); - - if (!mod_reference_cache.TryGetValue(id, out var mods)) - mod_reference_cache[id] = mods = GetAllMods().ToArray(); - - return mods; - } + public IEnumerable CreateAllMods() => Enum.GetValues(typeof(ModType)).Cast() + // Confine all mods of each mod type into a single IEnumerable + .SelectMany(GetModsFor) + // Filter out all null mods + .Where(mod => mod != null) + // Resolve MultiMods as their .Mods property + .SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod }); /// /// Returns a fresh instance of the mod matching the specified acronym. /// /// The acronym to query for . - public Mod GetModForAcronym(string acronym) + public Mod CreateModFromAcronym(string acronym) { - var type = GetAllModsForReference().FirstOrDefault(m => m.Acronym == acronym)?.GetType(); + var type = AllMods.FirstOrDefault(m => m.Acronym == acronym)?.GetType(); if (type != null) return (Mod)Activator.CreateInstance(type); @@ -88,10 +91,10 @@ namespace osu.Game.Rulesets /// /// Returns a fresh instance of the mod matching the specified type. /// - public T GetMod() + public T CreateMod() where T : Mod { - var type = GetAllModsForReference().FirstOrDefault(m => m is T)?.GetType(); + var type = AllMods.FirstOrDefault(m => m is T)?.GetType(); if (type != null) return (T)Activator.CreateInstance(type); @@ -179,7 +182,7 @@ namespace osu.Game.Rulesets } [CanBeNull] - public ModAutoplay GetAutoplayMod() => GetMod(); + public ModAutoplay GetAutoplayMod() => CreateMod(); public virtual ISkin CreateLegacySkinProvider([NotNull] ISkin skin, IBeatmap beatmap) => null; diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index 010f33e3ed..2e1a29372d 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -67,7 +67,7 @@ namespace osu.Game.Scoring.Legacy // lazer replays get a really high version number. if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION) - scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.GetMod()).ToArray(); + scoreInfo.Mods = scoreInfo.Mods.Append(currentRuleset.CreateMod()).ToArray(); currentBeatmap = workingBeatmap.GetPlayableBeatmap(currentRuleset.RulesetInfo, scoreInfo.Mods); scoreInfo.Beatmap = currentBeatmap.BeatmapInfo; diff --git a/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs b/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs index 54a83f4305..b7803f3420 100644 --- a/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs +++ b/osu.Game/Tests/Beatmaps/LegacyModConversionTest.cs @@ -34,7 +34,7 @@ namespace osu.Game.Tests.Beatmaps protected void TestToLegacy(LegacyMods expectedLegacyMods, Type[] providedModTypes) { var ruleset = CreateRuleset(); - var modInstances = ruleset.GetAllMods() + var modInstances = ruleset.CreateAllMods() .Where(mod => providedModTypes.Contains(mod.GetType())) .ToArray(); var actualLegacyMods = ruleset.ConvertToLegacyMods(modInstances); diff --git a/osu.Game/Tests/TestScoreInfo.cs b/osu.Game/Tests/TestScoreInfo.cs index 8ce71ace69..5ce6aae647 100644 --- a/osu.Game/Tests/TestScoreInfo.cs +++ b/osu.Game/Tests/TestScoreInfo.cs @@ -28,7 +28,7 @@ namespace osu.Game.Tests RulesetID = ruleset.ID ?? 0; Mods = excessMods - ? ruleset.CreateInstance().GetAllMods().ToArray() + ? ruleset.CreateInstance().CreateAllMods().ToArray() : new Mod[] { new TestModHardRock(), new TestModDoubleTime() }; TotalScore = 2845370; diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs index a31a6433ea..b34f7e2d5f 100644 --- a/osu.Game/Tests/Visual/PlayerTestScene.cs +++ b/osu.Game/Tests/Visual/PlayerTestScene.cs @@ -67,7 +67,7 @@ namespace osu.Game.Tests.Visual if (!AllowFail) { - var noFailMod = ruleset.GetMod(); + var noFailMod = ruleset.CreateMod(); if (noFailMod != null) SelectedMods.Value = new[] { noFailMod }; } From 76e877f1607d0aebcbfe3b5f91ded6ef10d941db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 11:22:08 +0900 Subject: [PATCH 910/961] Disable APIMod/Mod cross equality support --- .../Mods/ModSettingsEqualityComparison.cs | 33 ++++++++++++++----- osu.Game/Online/API/APIMod.cs | 5 ++- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Mods/ModSettingsEqualityComparison.cs b/osu.Game.Tests/Mods/ModSettingsEqualityComparison.cs index 7a5789f01a..ce6b3a68a5 100644 --- a/osu.Game.Tests/Mods/ModSettingsEqualityComparison.cs +++ b/osu.Game.Tests/Mods/ModSettingsEqualityComparison.cs @@ -3,6 +3,7 @@ using NUnit.Framework; using osu.Game.Online.API; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; namespace osu.Game.Tests.Mods @@ -11,26 +12,42 @@ namespace osu.Game.Tests.Mods public class ModSettingsEqualityComparison { [Test] - public void Test() + public void TestAPIMod() { + var apiMod1 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.25 } }); + var apiMod2 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } }); + var apiMod3 = new APIMod(new OsuModDoubleTime { SpeedChange = { Value = 1.26 } }); + + Assert.That(apiMod1, Is.Not.EqualTo(apiMod2)); + Assert.That(apiMod2, Is.EqualTo(apiMod2)); + Assert.That(apiMod2, Is.EqualTo(apiMod3)); + Assert.That(apiMod3, Is.EqualTo(apiMod2)); + } + + [Test] + public void TestMod() + { + var ruleset = new OsuRuleset(); + var mod1 = new OsuModDoubleTime { SpeedChange = { Value = 1.25 } }; var mod2 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } }; var mod3 = new OsuModDoubleTime { SpeedChange = { Value = 1.26 } }; - var apiMod1 = new APIMod(mod1); - var apiMod2 = new APIMod(mod2); - var apiMod3 = new APIMod(mod3); + + var doubleConvertedMod1 = new APIMod(mod1).ToMod(ruleset); + var doulbeConvertedMod2 = new APIMod(mod2).ToMod(ruleset); + var doulbeConvertedMod3 = new APIMod(mod3).ToMod(ruleset); Assert.That(mod1, Is.Not.EqualTo(mod2)); - Assert.That(apiMod1, Is.Not.EqualTo(apiMod2)); + Assert.That(doubleConvertedMod1, Is.Not.EqualTo(doulbeConvertedMod2)); Assert.That(mod2, Is.EqualTo(mod2)); - Assert.That(apiMod2, Is.EqualTo(apiMod2)); + Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod2)); Assert.That(mod2, Is.EqualTo(mod3)); - Assert.That(apiMod2, Is.EqualTo(apiMod3)); + Assert.That(doulbeConvertedMod2, Is.EqualTo(doulbeConvertedMod3)); Assert.That(mod3, Is.EqualTo(mod2)); - Assert.That(apiMod3, Is.EqualTo(apiMod2)); + Assert.That(doulbeConvertedMod3, Is.EqualTo(doulbeConvertedMod2)); } } } diff --git a/osu.Game/Online/API/APIMod.cs b/osu.Game/Online/API/APIMod.cs index 5e552dac09..62f9976c0f 100644 --- a/osu.Game/Online/API/APIMod.cs +++ b/osu.Game/Online/API/APIMod.cs @@ -16,7 +16,7 @@ using osu.Game.Utils; namespace osu.Game.Online.API { [MessagePackObject] - public class APIMod + public class APIMod : IEquatable { [JsonProperty("acronym")] [Key(0)] @@ -72,8 +72,7 @@ namespace osu.Game.Online.API if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; - return Acronym == other.Acronym && - Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default); + return Acronym == other.Acronym && Settings.SequenceEqual(other.Settings, ModSettingsEqualityComparer.Default); } public override string ToString() From f3299737985e1c3b7d3536762a829c7423a6ca05 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 10 Sep 2021 09:37:27 +0700 Subject: [PATCH 911/961] fix supporter promo background colour --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index c2b855a0f8..91ff314c15 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -53,6 +53,7 @@ namespace osu.Game.Overlays.Changelog Colour = Color4.Black.Opacity(0.25f), Offset = new Vector2(0, 1), Radius = 3, + Hollow = true, }, Children = new Drawable[] { From 9cf79a80c2235470911297a220057be860eadaa1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:00:41 +0900 Subject: [PATCH 912/961] Replace many more calls to `CreateAllMods` with more specific calls --- .../Visual/Gameplay/TestSceneAllRulesetPlayers.cs | 3 +-- .../Visual/SongSelect/TestSceneAdvancedStats.cs | 8 ++++---- .../Visual/UserInterface/TestSceneModSelectOverlay.cs | 4 ++-- .../Components/TestSceneTournamentModDisplay.cs | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs index 8487eecdfa..00b5c38e20 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneAllRulesetPlayers.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 NUnit.Framework; using osu.Framework.Allocation; using osu.Game.Configuration; @@ -71,7 +70,7 @@ namespace osu.Game.Tests.Visual.Gameplay var working = CreateWorkingBeatmap(rulesetInfo); Beatmap.Value = working; - SelectedMods.Value = new[] { ruleset.CreateAllMods().First(m => m is ModNoFail) }; + SelectedMods.Value = new[] { ruleset.CreateMod() }; Player = CreatePlayer(ruleset); diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs index 5e22bde1d5..dcc2111ad3 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneAdvancedStats.cs @@ -89,7 +89,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select EZ mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - SelectedMods.Value = new[] { ruleset.CreateAllMods().OfType().Single() }; + SelectedMods.Value = new[] { ruleset.CreateMod() }; }); AddAssert("circle size bar is blue", () => barIsBlue(advancedStats.FirstValue)); @@ -106,7 +106,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select HR mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - SelectedMods.Value = new[] { ruleset.CreateAllMods().OfType().Single() }; + SelectedMods.Value = new[] { ruleset.CreateMod() }; }); AddAssert("circle size bar is red", () => barIsRed(advancedStats.FirstValue)); @@ -123,7 +123,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select unchanged Difficulty Adjust mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - var difficultyAdjustMod = ruleset.CreateAllMods().OfType().Single(); + var difficultyAdjustMod = ruleset.CreateMod(); difficultyAdjustMod.ReadFromDifficulty(advancedStats.Beatmap.BaseDifficulty); SelectedMods.Value = new[] { difficultyAdjustMod }; }); @@ -142,7 +142,7 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("select changed Difficulty Adjust mod", () => { var ruleset = advancedStats.Beatmap.Ruleset.CreateInstance(); - var difficultyAdjustMod = ruleset.CreateAllMods().OfType().Single(); + var difficultyAdjustMod = ruleset.CreateMod(); var originalDifficulty = advancedStats.Beatmap.BaseDifficulty; difficultyAdjustMod.ReadFromDifficulty(originalDifficulty); diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 28e5644998..4f7aec3b67 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -158,8 +158,8 @@ namespace osu.Game.Tests.Visual.UserInterface var mania = new ManiaRuleset(); testModsWithSameBaseType( - mania.CreateAllMods().Single(m => m.GetType() == typeof(ManiaModFadeIn)), - mania.CreateAllMods().Single(m => m.GetType() == typeof(ManiaModHidden))); + mania.CreateMod(), + mania.CreateMod()); } [Test] diff --git a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs index cc1568f429..47e7ed9b61 100644 --- a/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs +++ b/osu.Game.Tournament.Tests/Components/TestSceneTournamentModDisplay.cs @@ -45,7 +45,7 @@ namespace osu.Game.Tournament.Tests.Components private void success(APIBeatmap apiBeatmap) { beatmap = apiBeatmap.ToBeatmap(rulesets); - var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().CreateAllMods(); + var mods = rulesets.GetRuleset(Ladder.Ruleset.Value.ID ?? 0).CreateInstance().AllMods; foreach (var mod in mods) { From 719392de394716856211931284b2fafe7d43c52e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:05:10 +0900 Subject: [PATCH 913/961] Change `CreateInstance` to use `Activator.CreateInstance` instead of clone --- osu.Game/Rulesets/Mods/IMod.cs | 2 +- osu.Game/Rulesets/Ruleset.cs | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs index ac17e49e60..ca5053aaca 100644 --- a/osu.Game/Rulesets/Mods/IMod.cs +++ b/osu.Game/Rulesets/Mods/IMod.cs @@ -27,6 +27,6 @@ namespace osu.Game.Rulesets.Mods /// /// Create a fresh instance based on this mod. /// - Mod CreateInstance() => ((Mod)this).DeepClone(); + Mod CreateInstance() => (Mod)Activator.CreateInstance(GetType()); } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 82707ad382..b0c3836774 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -80,12 +80,7 @@ namespace osu.Game.Rulesets /// The acronym to query for . public Mod CreateModFromAcronym(string acronym) { - var type = AllMods.FirstOrDefault(m => m.Acronym == acronym)?.GetType(); - - if (type != null) - return (Mod)Activator.CreateInstance(type); - - return null; + return AllMods.FirstOrDefault(m => m.Acronym == acronym)?.CreateInstance(); } /// @@ -94,12 +89,7 @@ namespace osu.Game.Rulesets public T CreateMod() where T : Mod { - var type = AllMods.FirstOrDefault(m => m is T)?.GetType(); - - if (type != null) - return (T)Activator.CreateInstance(type); - - return null; + return AllMods.FirstOrDefault(m => m is T)?.CreateInstance() as T; } public abstract IEnumerable GetModsFor(ModType type); From 8acf82944f2f83b84bd9bf0af18d3603bea8f1bb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 10 Sep 2021 10:17:03 +0700 Subject: [PATCH 914/961] use hex colour directly instead of transparency --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 91ff314c15..d3462c1787 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -53,14 +53,13 @@ namespace osu.Game.Overlays.Changelog Colour = Color4.Black.Opacity(0.25f), Offset = new Vector2(0, 1), Radius = 3, - Hollow = true, }, Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black.Opacity(0.3f), + Colour = Color4Extensions.FromHex("#222027"), }, new Container { From 2838a3a9614ecbf218e719a24444a6015e7e9c69 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 10 Sep 2021 12:25:41 +0900 Subject: [PATCH 915/961] Rewrite conditional to be more 'balanced' --- osu.Game/Users/Drawables/UpdateableAvatar.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index a8726d0cab..24d82c2784 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -69,20 +69,22 @@ namespace osu.Game.Users.Drawables if (user == null && !showGuestOnNull) return null; - if (!openOnClick) + if (openOnClick) + { + return new ClickableAvatar(user) + { + OpenOnClick = true, + ShowUsernameTooltip = showUsernameTooltip, + RelativeSizeAxes = Axes.Both, + }; + } + else { return new DrawableAvatar(user) { RelativeSizeAxes = Axes.Both, }; } - - return new ClickableAvatar(user) - { - OpenOnClick = openOnClick, - ShowUsernameTooltip = showUsernameTooltip, - RelativeSizeAxes = Axes.Both, - }; } } } From c3531e1361bcab20620eaec176792d5118da6f0d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:42:53 +0900 Subject: [PATCH 916/961] Move more specification from `Mod` to `IMod` --- osu.Game/Rulesets/Mods/IMod.cs | 15 +++++++++++++++ osu.Game/Rulesets/Mods/Mod.cs | 12 ------------ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/osu.Game/Rulesets/Mods/IMod.cs b/osu.Game/Rulesets/Mods/IMod.cs index ca5053aaca..d5d1de91de 100644 --- a/osu.Game/Rulesets/Mods/IMod.cs +++ b/osu.Game/Rulesets/Mods/IMod.cs @@ -13,6 +13,21 @@ namespace osu.Game.Rulesets.Mods /// string Acronym { get; } + /// + /// The name of this mod. + /// + string Name { get; } + + /// + /// The user readable description of this mod. + /// + string Description { get; } + + /// + /// The type of this mod. + /// + ModType Type { get; } + /// /// The icon of this mod. /// diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index fedee857c3..7136795461 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -22,29 +22,17 @@ namespace osu.Game.Rulesets.Mods [ExcludeFromDynamicCompile] public abstract class Mod : IMod, IEquatable, IDeepCloneable { - /// - /// The name of this mod. - /// [JsonIgnore] public abstract string Name { get; } - /// - /// The shortened name of this mod. - /// public abstract string Acronym { get; } [JsonIgnore] public virtual IconUsage? Icon => null; - /// - /// The type of this mod. - /// [JsonIgnore] public virtual ModType Type => ModType.Fun; - /// - /// The user readable description of this mod. - /// [JsonIgnore] public abstract string Description { get; } From 464797fecf8afdd604d31012f6ff378da49326e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:43:12 +0900 Subject: [PATCH 917/961] Allow `ModIcon` to be constructed using an `IMod` --- .../Visual/UserInterface/TestSceneModIcon.cs | 13 +++++++++++++ osu.Game/Rulesets/UI/ModIcon.cs | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs index e7fa7d9235..513eb2fafc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModIcon.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; +using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.UI; @@ -17,5 +19,16 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("create mod icon", () => Child = icon = new ModIcon(new OsuModDoubleTime())); AddStep("change mod", () => icon.Mod = new OsuModEasy()); } + + [Test] + public void TestInterfaceModType() + { + ModIcon icon = null; + + var ruleset = new OsuRuleset(); + + AddStep("create mod icon", () => Child = icon = new ModIcon(ruleset.AllMods.First(m => m.Acronym == "DT"))); + AddStep("change mod", () => icon.Mod = ruleset.AllMods.First(m => m.Acronym == "EZ")); + } } } diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 725cfa9c26..79bada0490 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -30,12 +30,12 @@ namespace osu.Game.Rulesets.UI private const float size = 80; - public virtual LocalisableString TooltipText => showTooltip ? mod.IconTooltip : null; + public virtual LocalisableString TooltipText => showTooltip ? ((mod as Mod)?.IconTooltip ?? mod.Name) : null; - private Mod mod; + private IMod mod; private readonly bool showTooltip; - public Mod Mod + public IMod Mod { get => mod; set @@ -58,7 +58,7 @@ namespace osu.Game.Rulesets.UI /// /// The mod to be displayed /// Whether a tooltip describing the mod should display on hover. - public ModIcon(Mod mod, bool showTooltip = true) + public ModIcon(IMod mod, bool showTooltip = true) { this.mod = mod ?? throw new ArgumentNullException(nameof(mod)); this.showTooltip = showTooltip; @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.UI updateMod(mod); } - private void updateMod(Mod value) + private void updateMod(IMod value) { modAcronym.Text = value.Acronym; modIcon.Icon = value.Icon ?? FontAwesome.Solid.Question; From 28e93291364cbe78d94aceaee284eb5a488f34db Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:43:21 +0900 Subject: [PATCH 918/961] Update `LeaderboardModSelector` to avoid creating mod instances --- osu.Game/Online/API/Requests/GetScoresRequest.cs | 6 +++--- osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetScoresRequest.cs b/osu.Game/Online/API/Requests/GetScoresRequest.cs index bf3441d2a0..b4e0e44b2c 100644 --- a/osu.Game/Online/API/Requests/GetScoresRequest.cs +++ b/osu.Game/Online/API/Requests/GetScoresRequest.cs @@ -18,9 +18,9 @@ namespace osu.Game.Online.API.Requests private readonly BeatmapInfo beatmap; private readonly BeatmapLeaderboardScope scope; private readonly RulesetInfo ruleset; - private readonly IEnumerable mods; + private readonly IEnumerable mods; - public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null) + public GetScoresRequest(BeatmapInfo beatmap, RulesetInfo ruleset, BeatmapLeaderboardScope scope = BeatmapLeaderboardScope.Global, IEnumerable mods = null) { if (!beatmap.OnlineBeatmapID.HasValue) throw new InvalidOperationException($"Cannot lookup a beatmap's scores without having a populated {nameof(BeatmapInfo.OnlineBeatmapID)}."); @@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests this.beatmap = beatmap; this.scope = scope; this.ruleset = ruleset ?? throw new ArgumentNullException(nameof(ruleset)); - this.mods = mods ?? Array.Empty(); + this.mods = mods ?? Array.Empty(); Success += onSuccess; } diff --git a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs index 2683d7bc6d..6349f115cb 100644 --- a/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs +++ b/osu.Game/Overlays/BeatmapSet/LeaderboardModSelector.cs @@ -19,7 +19,7 @@ namespace osu.Game.Overlays.BeatmapSet { public class LeaderboardModSelector : CompositeDrawable { - public readonly BindableList SelectedMods = new BindableList(); + public readonly BindableList SelectedMods = new BindableList(); public readonly Bindable Ruleset = new Bindable(); private readonly FillFlowContainer modsContainer; @@ -54,7 +54,7 @@ namespace osu.Game.Overlays.BeatmapSet return; modsContainer.Add(new ModButton(new ModNoMod())); - modsContainer.AddRange(ruleset.NewValue.CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m.CreateInstance()))); + modsContainer.AddRange(ruleset.NewValue.CreateInstance().AllMods.Where(m => m.UserPlayable).Select(m => new ModButton(m))); modsContainer.ForEach(button => { @@ -76,7 +76,7 @@ namespace osu.Game.Overlays.BeatmapSet updateHighlighted(); } - private void selectionChanged(Mod mod, bool selected) + private void selectionChanged(IMod mod, bool selected) { if (selected) SelectedMods.Add(mod); @@ -101,9 +101,9 @@ namespace osu.Game.Overlays.BeatmapSet private const int duration = 200; public readonly BindableBool Highlighted = new BindableBool(); - public Action OnSelectionChanged; + public Action OnSelectionChanged; - public ModButton(Mod mod) + public ModButton(IMod mod) : base(mod) { Scale = new Vector2(0.4f); From 212c3c699c3a3661904c6b502afd49cea327353e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 12:58:12 +0900 Subject: [PATCH 919/961] Reword xmldoc slightly --- osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs index bf8063cfaf..3658dbab83 100644 --- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs @@ -92,8 +92,8 @@ namespace osu.Game.Beatmaps public BeatmapSetOnlineLanguage Language { get; set; } /// - /// The song ID of this beatmap set. - /// Non-null only if the song is from a featured artist. + /// The track ID of this beatmap set. + /// Non-null only if the track is linked to a featured artist track entry. /// public int? TrackId { get; set; } } From e636692596e8043826a1c461b4f5afd7c53f2589 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 10 Sep 2021 11:00:55 +0700 Subject: [PATCH 920/961] change background to background 5 --- osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index d3462c1787..6780cf4016 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -28,6 +28,7 @@ namespace osu.Game.Overlays.Changelog private readonly FillFlowContainer textContainer; private readonly Container imageContainer; + private readonly Box background; public ChangelogSupporterPromo() { @@ -56,10 +57,9 @@ namespace osu.Game.Overlays.Changelog }, Children = new Drawable[] { - new Box + background = new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4Extensions.FromHex("#222027"), }, new Container { @@ -92,8 +92,10 @@ namespace osu.Game.Overlays.Changelog } [BackgroundDependencyLoader] - private void load(OsuColour colour, TextureStore textures) + private void load(OsuColour colour, TextureStore textures, OverlayColourProvider colourProvider) { + background.Colour = colourProvider.Background5; + SupporterPromoLinkFlowContainer supportLinkText; textContainer.Children = new Drawable[] { From 85b699182e1f9254a45f141988a22bf60898c54d Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 10 Sep 2021 13:01:54 +0900 Subject: [PATCH 921/961] Rename variable to be more descriptive --- osu.Game/Users/Drawables/UpdateableAvatar.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Users/Drawables/UpdateableAvatar.cs b/osu.Game/Users/Drawables/UpdateableAvatar.cs index 24d82c2784..6d48104131 100644 --- a/osu.Game/Users/Drawables/UpdateableAvatar.cs +++ b/osu.Game/Users/Drawables/UpdateableAvatar.cs @@ -44,7 +44,7 @@ namespace osu.Game.Users.Drawables protected override double LoadDelay => 200; - private readonly bool openOnClick; + private readonly bool isInteractive; private readonly bool showUsernameTooltip; private readonly bool showGuestOnNull; @@ -52,12 +52,12 @@ namespace osu.Game.Users.Drawables /// Construct a new UpdateableAvatar. /// /// The initial user to display. - /// Whether to open the user's profile when clicked. - /// Whether to show the username rather than "view profile" on the tooltip. + /// If set to true, hover/click sounds will play and clicking the avatar will open the user's profile. + /// Whether to show the username rather than "view profile" on the tooltip. (note: this only applies if is also true) /// Whether to show a default guest representation on null user (as opposed to nothing). - public UpdateableAvatar(User user = null, bool openOnClick = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) + public UpdateableAvatar(User user = null, bool isInteractive = true, bool showUsernameTooltip = false, bool showGuestOnNull = true) { - this.openOnClick = openOnClick; + this.isInteractive = isInteractive; this.showUsernameTooltip = showUsernameTooltip; this.showGuestOnNull = showGuestOnNull; @@ -69,7 +69,7 @@ namespace osu.Game.Users.Drawables if (user == null && !showGuestOnNull) return null; - if (openOnClick) + if (isInteractive) { return new ClickableAvatar(user) { From 110f495345176873676462ee07349b9498f5120b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 10 Sep 2021 11:11:55 +0700 Subject: [PATCH 922/961] move internal children to bdl --- .../Changelog/ChangelogSupporterPromo.cs | 148 +++++++++--------- 1 file changed, 71 insertions(+), 77 deletions(-) diff --git a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs index 6780cf4016..1b0a62dc4a 100644 --- a/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs +++ b/osu.Game/Overlays/Changelog/ChangelogSupporterPromo.cs @@ -26,10 +26,6 @@ namespace osu.Game.Overlays.Changelog private const float image_container_width = 164; private const float heart_size = 75; - private readonly FillFlowContainer textContainer; - private readonly Container imageContainer; - private readonly Box background; - public ChangelogSupporterPromo() { RelativeSizeAxes = Axes.X; @@ -39,6 +35,12 @@ namespace osu.Game.Overlays.Changelog Vertical = 20, Horizontal = 50, }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colour, TextureStore textures, OverlayColourProvider colourProvider) + { + SupporterPromoLinkFlowContainer supportLinkText; InternalChildren = new Drawable[] { @@ -57,9 +59,10 @@ namespace osu.Game.Overlays.Changelog }, Children = new Drawable[] { - background = new Box + new Box { RelativeSizeAxes = Axes.Both, + Colour = colourProvider.Background5, }, new Container { @@ -68,7 +71,7 @@ namespace osu.Game.Overlays.Changelog Padding = new MarginPadding { Horizontal = 75 }, Children = new Drawable[] { - textContainer = new FillFlowContainer + new FillFlowContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -76,93 +79,84 @@ namespace osu.Game.Overlays.Changelog Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Padding = new MarginPadding { Right = 50 + image_container_width }, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = ChangelogStrings.SupportHeading, + Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), + Margin = new MarginPadding { Bottom = 20 }, + }, + supportLinkText = new SupporterPromoLinkFlowContainer(t => + { + t.Font = t.Font.With(size: 14); + t.Colour = colour.PinkLighter; + }) + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }, + new OsuTextFlowContainer(t => + { + t.Font = t.Font.With(size: 12); + t.Colour = colour.PinkLighter; + }) + { + Text = ChangelogStrings.SupportText2.ToString(), + Margin = new MarginPadding { Top = 10 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }, }, - imageContainer = new Container + new Container { RelativeSizeAxes = Axes.Y, Width = image_container_width, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, + Children = new Drawable[] + { + new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Margin = new MarginPadding { Bottom = 28 }, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fill, + Texture = textures.Get(@"Online/supporter-pippi"), + }, + new Container + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + Size = new Vector2(heart_size), + Margin = new MarginPadding { Top = 70 }, + Masking = true, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = colour.Pink, + Radius = 10, + Roundness = heart_size / 2, + }, + Child = new Sprite + { + Size = new Vector2(heart_size), + Texture = textures.Get(@"Online/supporter-heart"), + }, + }, + } } } }, } }, }; - } - - [BackgroundDependencyLoader] - private void load(OsuColour colour, TextureStore textures, OverlayColourProvider colourProvider) - { - background.Colour = colourProvider.Background5; - - SupporterPromoLinkFlowContainer supportLinkText; - textContainer.Children = new Drawable[] - { - new OsuSpriteText - { - Text = ChangelogStrings.SupportHeading, - Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light), - Margin = new MarginPadding { Bottom = 20 }, - }, - supportLinkText = new SupporterPromoLinkFlowContainer(t => - { - t.Font = t.Font.With(size: 14); - t.Colour = colour.PinkLighter; - }) - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - }, - new OsuTextFlowContainer(t => - { - t.Font = t.Font.With(size: 12); - t.Colour = colour.PinkLighter; - }) - { - Text = ChangelogStrings.SupportText2.ToString(), - Margin = new MarginPadding { Top = 10 }, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } - }; supportLinkText.AddText("Support further development of osu! and "); supportLinkText.AddLink("become an osu!supporter", @"https://osu.ppy.sh/home/support", t => t.Font = t.Font.With(weight: FontWeight.Bold)); supportLinkText.AddText(" today!"); - - imageContainer.Children = new Drawable[] - { - new Sprite - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Margin = new MarginPadding { Bottom = 28 }, - RelativeSizeAxes = Axes.Both, - FillMode = FillMode.Fill, - Texture = textures.Get(@"Online/supporter-pippi"), - }, - new Container - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - Size = new Vector2(heart_size), - Margin = new MarginPadding { Top = 70 }, - Masking = true, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = colour.Pink, - Radius = 10, - Roundness = heart_size / 2, - }, - Child = new Sprite - { - Size = new Vector2(heart_size), - Texture = textures.Get(@"Online/supporter-heart"), - }, - }, - }; } private class SupporterPromoLinkFlowContainer : LinkFlowContainer From 8d1e43423eb5870746db19a4c178d6005e0ffc80 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 10 Sep 2021 14:18:40 +0900 Subject: [PATCH 923/961] Update calls to use new variable name --- osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarUserButton.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index cf930e985c..f5720cffb0 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -61,7 +61,7 @@ namespace osu.Game.Overlays.Profile.Header Origin = Anchor.CentreLeft, Children = new Drawable[] { - avatar = new UpdateableAvatar(openOnClick: false, showGuestOnNull: false) + avatar = new UpdateableAvatar(isInteractive: false, showGuestOnNull: false) { Size = new Vector2(avatar_size), Masking = true, diff --git a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs index 165c095514..5d4430caa2 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarUserButton.cs @@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Toolbar Add(new OpaqueBackground { Depth = 1 }); - Flow.Add(avatar = new UpdateableAvatar(openOnClick: false) + Flow.Add(avatar = new UpdateableAvatar(isInteractive: false) { Masking = true, Size = new Vector2(32), From 84c152e7b6f7d3320a2dcc4f14f15b8485b29430 Mon Sep 17 00:00:00 2001 From: rednir Date: Fri, 10 Sep 2021 08:01:38 +0100 Subject: [PATCH 924/961] break when already found user Co-authored-by: Salman Ahmed --- osu.Game/Online/Chat/ChannelManager.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 34c6d048a3..3737451140 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -268,8 +268,12 @@ namespace osu.Game.Online.Chat // Check if the user has joined requested channel already. var alreadyJoinedChannel = JoinedChannels.FirstOrDefault( c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase)); + if (alreadyJoinedChannel != null) + { CurrentChannel.Value = alreadyJoinedChannel; + break; + } var request = new GetUserRequest(content); request.Success += OpenPrivateChannel; From 5ec615c7830af66959e2b99b9a36df0b1aebd205 Mon Sep 17 00:00:00 2001 From: rednir Date: Fri, 10 Sep 2021 08:02:15 +0100 Subject: [PATCH 925/961] display user in error message Co-authored-by: Salman Ahmed --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 3737451140..9ecbc40ce2 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -277,7 +277,7 @@ namespace osu.Game.Online.Chat var request = new GetUserRequest(content); request.Success += OpenPrivateChannel; - request.Failure += _ => target.AddNewMessages(new ErrorMessage("User not found.")); + request.Failure += _ => target.AddNewMessages(new ErrorMessage($"User '{content}' was not found.")); api.Queue(request); break; From acb181ff2b6174aa04f0f4b88cc798ea557ad56a Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Fri, 10 Sep 2021 08:15:43 +0100 Subject: [PATCH 926/961] rename `alreadyJoinedChannel` -> `privateChannel` --- osu.Game/Online/Chat/ChannelManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 9ecbc40ce2..347f0af605 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -266,12 +266,12 @@ namespace osu.Game.Online.Chat } // Check if the user has joined requested channel already. - var alreadyJoinedChannel = JoinedChannels.FirstOrDefault( + var privateChannel = JoinedChannels.FirstOrDefault( c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase)); - if (alreadyJoinedChannel != null) + if (privateChannel != null) { - CurrentChannel.Value = alreadyJoinedChannel; + CurrentChannel.Value = privateChannel; break; } From 5a069546656e88d48501d7e4536f9fed42871c1e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 18:16:10 +0900 Subject: [PATCH 927/961] Add test coverage of game exit scenario --- .../Visual/Navigation/TestSceneScreenNavigation.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs index b536233ff0..cc64d37116 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneScreenNavigation.cs @@ -15,6 +15,7 @@ using osu.Game.Overlays.Mods; using osu.Game.Overlays.Toolbar; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Components; using osu.Game.Screens.OnlinePlay.Lounge; using osu.Game.Screens.Play; @@ -388,6 +389,19 @@ namespace osu.Game.Tests.Visual.Navigation AddAssert("now playing is hidden", () => nowPlayingOverlay.State.Value == Visibility.Hidden); } + [Test] + public void TestExitGameFromSongSelect() + { + PushAndConfirm(() => new TestPlaySongSelect()); + exitViaEscapeAndConfirm(); + + pushEscape(); // returns to osu! logo + + AddStep("Hold escape", () => InputManager.PressKey(Key.Escape)); + AddUntilStep("Wait for intro", () => Game.ScreenStack.CurrentScreen is IntroTriangles); + AddUntilStep("Wait for game exit", () => Game.ScreenStack.CurrentScreen == null); + } + private void pushEscape() => AddStep("Press escape", () => InputManager.Key(Key.Escape)); From 94702ee7e3bb1df48a9a07ab63e07bfb059b9f7e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Sep 2021 18:10:03 +0900 Subject: [PATCH 928/961] Fix triangles intro attempting to restart track after it is disposed --- osu.Game/Screens/Menu/IntroTriangles.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs index 36296487a8..a8ca17cec1 100644 --- a/osu.Game/Screens/Menu/IntroTriangles.cs +++ b/osu.Game/Screens/Menu/IntroTriangles.cs @@ -42,6 +42,7 @@ namespace osu.Game.Screens.Menu private Sample welcome; private DecoupleableInterpolatingFramedClock decoupledClock; + private TrianglesIntroSequence intro; [BackgroundDependencyLoader] private void load() @@ -66,7 +67,7 @@ namespace osu.Game.Screens.Menu if (UsingThemedIntro) decoupledClock.ChangeSource(Track); - LoadComponentAsync(new TrianglesIntroSequence(logo, background) + LoadComponentAsync(intro = new TrianglesIntroSequence(logo, background) { RelativeSizeAxes = Axes.Both, Clock = decoupledClock, @@ -82,6 +83,14 @@ namespace osu.Game.Screens.Menu } } + public override void OnSuspending(IScreen next) + { + base.OnSuspending(next); + + // important as there is a clock attached to a track which will likely be disposed before returning to this screen. + intro.Expire(); + } + public override void OnResuming(IScreen last) { base.OnResuming(last); From 0e5659acb29789a6cde29fdd0fa84a4f8c4f563d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 11 Sep 2021 14:10:29 +0200 Subject: [PATCH 929/961] Remove leftover exception throw --- osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index fac0661a15..2cb696be0a 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -71,7 +71,6 @@ namespace osu.Game.Graphics.UserInterfaceV2 public void OnReleased(GlobalAction action) { - throw new System.NotImplementedException(); } } } From c166f1a06ab09e2309284429f69f9f673ec594d0 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 11 Sep 2021 14:18:09 +0100 Subject: [PATCH 930/961] change error message based on exception message --- osu.Game/Online/Chat/ChannelManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 347f0af605..ffbd34abde 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -277,7 +277,9 @@ namespace osu.Game.Online.Chat var request = new GetUserRequest(content); request.Success += OpenPrivateChannel; - request.Failure += _ => target.AddNewMessages(new ErrorMessage($"User '{content}' was not found.")); + request.Failure += e => target.AddNewMessages( + new ErrorMessage(e.InnerException?.Message == "NotFound" ? $"User '{content}' was not found." : "Could not fetch user.")); + api.Queue(request); break; From 1b264a2dd0ec1a08bfd0662f3e47d792a40b91db Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 11 Sep 2021 16:22:29 +0100 Subject: [PATCH 931/961] make user lookup string public --- osu.Game/Online/API/Requests/GetUserRequest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/API/Requests/GetUserRequest.cs b/osu.Game/Online/API/Requests/GetUserRequest.cs index fe954372bf..730e4e02ed 100644 --- a/osu.Game/Online/API/Requests/GetUserRequest.cs +++ b/osu.Game/Online/API/Requests/GetUserRequest.cs @@ -8,7 +8,7 @@ namespace osu.Game.Online.API.Requests { public class GetUserRequest : APIRequest { - private readonly string lookup; + public readonly string Lookup; public readonly RulesetInfo Ruleset; private readonly LookupType lookupType; @@ -26,7 +26,7 @@ namespace osu.Game.Online.API.Requests /// The ruleset to get the user's info for. public GetUserRequest(long? userId = null, RulesetInfo ruleset = null) { - lookup = userId.ToString(); + Lookup = userId.ToString(); lookupType = LookupType.Id; Ruleset = ruleset; } @@ -38,12 +38,12 @@ namespace osu.Game.Online.API.Requests /// The ruleset to get the user's info for. public GetUserRequest(string username = null, RulesetInfo ruleset = null) { - lookup = username; + Lookup = username; lookupType = LookupType.Username; Ruleset = ruleset; } - protected override string Target => lookup != null ? $@"users/{lookup}/{Ruleset?.ShortName}?key={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; + protected override string Target => Lookup != null ? $@"users/{Lookup}/{Ruleset?.ShortName}?key={lookupType.ToString().ToLower()}" : $@"me/{Ruleset?.ShortName}"; private enum LookupType { From 7924a990a346a4f98e5884e4b2d071da6d0b21f6 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 11 Sep 2021 16:22:35 +0100 Subject: [PATCH 932/961] add tests for /chat command --- .../Visual/Online/TestSceneChatOverlay.cs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 7cfca31167..90263e9deb 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -85,6 +86,21 @@ namespace osu.Game.Tests.Visual.Online case JoinChannelRequest joinChannel: joinChannel.TriggerSuccess(); return true; + + case GetUserRequest getUser: + if (getUser.Lookup.Equals("some body", StringComparison.OrdinalIgnoreCase)) + { + getUser.TriggerSuccess(new User() + { + Username = "some body", + Id = 1, + }); + } + else + { + getUser.TriggerFailure(new Exception()); + } + return true; } return false; @@ -322,6 +338,27 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Current channel is channel 1", () => currentChannel == channel1); } + [Test] + public void TestChatCommand() + { + AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); + AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); + + AddStep("Open chat with user.", () => channelManager.PostCommand("chat some body")); + AddAssert("PM channel is selected", () => + channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body"); + + AddStep("Open chat with non-existant user", () => channelManager.PostCommand("chat nobody")); + AddAssert("Last message is error", () => channelManager.CurrentChannel.Value.Messages.Last().GetType() == typeof(ErrorMessage)); + + // Make sure no unnecessary requests are made when the PM chanenl is already open. + AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); + AddStep("Unregister request handling", () => ((DummyAPIAccess)API).HandleRequest = null); + AddStep("Open chat with user.", () => channelManager.PostCommand("chat some body")); + AddAssert("PM channel is selected", () => + channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body"); + } + private void pressChannelHotkey(int number) { var channelKey = Key.Number0 + number; From 605933c46722181edeb4c4280df9cc5df4661f92 Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 11 Sep 2021 16:23:17 +0100 Subject: [PATCH 933/961] typo --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 90263e9deb..e546575319 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -351,7 +351,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Open chat with non-existant user", () => channelManager.PostCommand("chat nobody")); AddAssert("Last message is error", () => channelManager.CurrentChannel.Value.Messages.Last().GetType() == typeof(ErrorMessage)); - // Make sure no unnecessary requests are made when the PM chanenl is already open. + // Make sure no unnecessary requests are made when the PM channel is already open. AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); AddStep("Unregister request handling", () => ((DummyAPIAccess)API).HandleRequest = null); AddStep("Open chat with user.", () => channelManager.PostCommand("chat some body")); From eeaa8a838076040a0bb1e7f659e83ebbbaad71bd Mon Sep 17 00:00:00 2001 From: Davran Dilshat Date: Sat, 11 Sep 2021 16:47:20 +0100 Subject: [PATCH 934/961] code quality --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index e546575319..9200b5b3dd 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -90,7 +90,7 @@ namespace osu.Game.Tests.Visual.Online case GetUserRequest getUser: if (getUser.Lookup.Equals("some body", StringComparison.OrdinalIgnoreCase)) { - getUser.TriggerSuccess(new User() + getUser.TriggerSuccess(new User { Username = "some body", Id = 1, @@ -100,6 +100,7 @@ namespace osu.Game.Tests.Visual.Online { getUser.TriggerFailure(new Exception()); } + return true; } From b9c127c07ef27aebaffed87e94457aaa057ce9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 11 Sep 2021 15:54:49 +0200 Subject: [PATCH 935/961] Improve content transitions in beatmap listing --- osu.Game/Overlays/BeatmapListingOverlay.cs | 27 +++++++++++----------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 6861d17f26..935a89b99b 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -75,6 +75,7 @@ namespace osu.Game.Overlays { AutoSizeAxes = Axes.Y, RelativeSizeAxes = Axes.X, + Masking = true, Padding = new MarginPadding { Horizontal = 20 }, Children = new Drawable[] { @@ -186,21 +187,16 @@ namespace osu.Game.Overlays if (lastContent != null) { - var transform = lastContent.FadeOut(100, Easing.OutQuint); + lastContent.FadeOut(100, Easing.OutQuint); - if (lastContent == notFoundContent || lastContent == supporterRequiredContent) - { - // the placeholders may be used multiple times, so don't expire/dispose them. - transform.Schedule(() => panelTarget.Remove(lastContent)); - } - else - { - // Consider the case when the new content is smaller than the last content. - // If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird. - // At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0. - // To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so. - lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y).Then().Schedule(() => lastContent.Expire()); - } + // Consider the case when the new content is smaller than the last content. + // If the auto-size computation is delayed until fade out completes, the background remain high for too long making the resulting transition to the smaller height look weird. + // At the same time, if the last content's height is bypassed immediately, there is a period where the new content is at Alpha = 0 when the auto-sized height will be 0. + // To resolve both of these issues, the bypass is delayed until a point when the content transitions (fade-in and fade-out) overlap and it looks good to do so. + var sequence = lastContent.Delay(25).Schedule(() => lastContent.BypassAutoSizeAxes = Axes.Y); + + if (lastContent != notFoundContent && lastContent != supporterRequiredContent) + sequence.Then().Schedule(() => lastContent.Expire()); } if (!content.IsAlive) @@ -208,6 +204,9 @@ namespace osu.Game.Overlays content.FadeInFromZero(200, Easing.OutQuint); currentContent = content; + // currentContent may be one of the placeholders, and still have BypassAutoSizeAxes set to Y from the last fade-out. + // restore to the initial state. + currentContent.BypassAutoSizeAxes = Axes.None; } protected override void Dispose(bool isDisposing) From e511c2ef2b0be57fbdc4ffb8d899eaa3ddac891a Mon Sep 17 00:00:00 2001 From: rednir Date: Sun, 12 Sep 2021 08:50:53 +0100 Subject: [PATCH 936/961] add comment --- osu.Game/Online/Chat/ChannelManager.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index ffbd34abde..853c28c7c8 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -265,7 +265,8 @@ namespace osu.Game.Online.Chat break; } - // Check if the user has joined requested channel already. + // Check if the user has joined the requested channel already. + // This uses the channel name for comparison as the PM user's username is unavailable after a restart. var privateChannel = JoinedChannels.FirstOrDefault( c => c.Type == ChannelType.PM && c.Users.Count == 1 && c.Name.Equals(content, StringComparison.OrdinalIgnoreCase)); From c4627bed6dbf713369273026f2ee946ad68895af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 12:56:36 +0200 Subject: [PATCH 937/961] Print username in case of generic network failure too --- osu.Game/Online/Chat/ChannelManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 853c28c7c8..47d5955fb0 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -279,7 +279,7 @@ namespace osu.Game.Online.Chat var request = new GetUserRequest(content); request.Success += OpenPrivateChannel; request.Failure += e => target.AddNewMessages( - new ErrorMessage(e.InnerException?.Message == "NotFound" ? $"User '{content}' was not found." : "Could not fetch user.")); + new ErrorMessage(e.InnerException?.Message == @"NotFound" ? $"User '{content}' was not found." : $"Could not fetch user '{content}'.")); api.Queue(request); break; From 3467b1f60c9d3f3c3fae1c75cda9702316fec4d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 13:00:52 +0200 Subject: [PATCH 938/961] Retouch chat command test slightly --- osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs index 9200b5b3dd..609e637914 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlay.cs @@ -345,17 +345,17 @@ namespace osu.Game.Tests.Visual.Online AddStep("Join channel 1", () => channelManager.JoinChannel(channel1)); AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); - AddStep("Open chat with user.", () => channelManager.PostCommand("chat some body")); + AddStep("Open chat with user", () => channelManager.PostCommand("chat some body")); AddAssert("PM channel is selected", () => channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body"); - AddStep("Open chat with non-existant user", () => channelManager.PostCommand("chat nobody")); - AddAssert("Last message is error", () => channelManager.CurrentChannel.Value.Messages.Last().GetType() == typeof(ErrorMessage)); + AddStep("Open chat with non-existent user", () => channelManager.PostCommand("chat nobody")); + AddAssert("Last message is error", () => channelManager.CurrentChannel.Value.Messages.Last() is ErrorMessage); // Make sure no unnecessary requests are made when the PM channel is already open. AddStep("Select channel 1", () => clickDrawable(chatOverlay.TabMap[channel1])); AddStep("Unregister request handling", () => ((DummyAPIAccess)API).HandleRequest = null); - AddStep("Open chat with user.", () => channelManager.PostCommand("chat some body")); + AddStep("Open chat with user", () => channelManager.PostCommand("chat some body")); AddAssert("PM channel is selected", () => channelManager.CurrentChannel.Value.Type == ChannelType.PM && channelManager.CurrentChannel.Value.Users.Single().Username == "some body"); } From 8357efc74fbaaf0e244ab8ce52d4a44e41995d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 11 Sep 2021 20:43:17 +0200 Subject: [PATCH 939/961] Make `EditorTestScene` go through `EditorLoader` --- osu.Game/Screens/Edit/EditorLoader.cs | 28 +++++++++++---------- osu.Game/Tests/Visual/EditorTestScene.cs | 31 +++++++++++++++++++++--- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Edit/EditorLoader.cs b/osu.Game/Screens/Edit/EditorLoader.cs index aec7d32939..6bbfa92c3b 100644 --- a/osu.Game/Screens/Edit/EditorLoader.cs +++ b/osu.Game/Screens/Edit/EditorLoader.cs @@ -34,6 +34,20 @@ namespace osu.Game.Screens.Edit [CanBeNull] private ScheduledDelegate scheduledDifficultySwitch; + [BackgroundDependencyLoader] + private void load() + { + AddRangeInternal(new Drawable[] + { + new LoadingSpinner(true) + { + State = { Value = Visibility.Visible }, + } + }); + } + + protected virtual Editor CreateEditor() => new Editor(this); + protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); @@ -47,18 +61,6 @@ namespace osu.Game.Screens.Edit } } - [BackgroundDependencyLoader] - private void load() - { - AddRangeInternal(new Drawable[] - { - new LoadingSpinner(true) - { - State = { Value = Visibility.Visible }, - } - }); - } - public void ScheduleDifficultySwitch(BeatmapInfo beatmapInfo) { scheduledDifficultySwitch?.Cancel(); @@ -81,7 +83,7 @@ namespace osu.Game.Screens.Edit private void pushEditor() { - this.Push(new Editor(this)); + this.Push(CreateEditor()); ValidForResume = false; } diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index a393802309..9fb9df39a8 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -16,6 +16,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Edit; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Compose.Components.Timeline; +using osu.Game.Screens.Menu; using osu.Game.Skinning; namespace osu.Game.Tests.Visual @@ -24,7 +25,9 @@ namespace osu.Game.Tests.Visual { protected EditorBeatmap EditorBeatmap; - protected TestEditor Editor { get; private set; } + private TestEditorLoader editorLoader; + + protected TestEditor Editor => editorLoader.Editor; protected EditorClock EditorClock { get; private set; } @@ -33,9 +36,19 @@ namespace osu.Game.Tests.Visual /// protected virtual bool IsolateSavingFromDatabase => true; + // required for screen transitions to work properly + // (see comment in EditorLoader.LogoArriving). + [Cached] + private OsuLogo logo = new OsuLogo + { + Alpha = 0 + }; + [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio, RulesetStore rulesets) { + Add(logo); + var working = CreateWorkingBeatmap(Ruleset.Value); Beatmap.Value = working; @@ -59,7 +72,7 @@ namespace osu.Game.Tests.Visual protected virtual void LoadEditor() { - LoadScreen(Editor = CreateEditor()); + LoadScreen(editorLoader = new TestEditorLoader()); } /// @@ -70,7 +83,14 @@ namespace osu.Game.Tests.Visual protected sealed override Ruleset CreateRuleset() => CreateEditorRuleset(); - protected virtual TestEditor CreateEditor() => new TestEditor(); + protected class TestEditorLoader : EditorLoader + { + public TestEditor Editor { get; private set; } + + protected sealed override Editor CreateEditor() => Editor = CreateTestEditor(this); + + protected virtual TestEditor CreateTestEditor(EditorLoader loader) => new TestEditor(loader); + } protected class TestEditor : Editor { @@ -87,6 +107,11 @@ namespace osu.Game.Tests.Visual public new void Paste() => base.Paste(); public new bool HasUnsavedChanges => base.HasUnsavedChanges; + + public TestEditor(EditorLoader loader = null) + : base(loader) + { + } } private class TestBeatmapManager : BeatmapManager From 5ae2f419304d95505308888f10a64e5a867e699d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 11 Sep 2021 21:07:34 +0200 Subject: [PATCH 940/961] Make difficulty switching test scene use `EditorTestScene` --- .../Editing/TestSceneDifficultySwitching.cs | 54 +++++++------------ 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index 0f3d413a7d..587c37c6f5 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -9,26 +9,20 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Dialog; +using osu.Game.Rulesets; +using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Components.Menus; -using osu.Game.Screens.Menu; using osu.Game.Tests.Beatmaps.IO; using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { - public class TestSceneDifficultySwitching : ScreenTestScene + public class TestSceneDifficultySwitching : EditorTestScene { - private BeatmapSetInfo importedBeatmapSet; - private Editor editor; + protected override Ruleset CreateEditorRuleset() => new OsuRuleset(); - // required for screen transitions to work properly - // (see comment in EditorLoader.LogoArriving). - [Cached] - private OsuLogo logo = new OsuLogo - { - Alpha = 0 - }; + protected override bool IsolateSavingFromDatabase => false; [Resolved] private OsuGameBase game { get; set; } @@ -36,20 +30,18 @@ namespace osu.Game.Tests.Visual.Editing [Resolved] private BeatmapManager beatmaps { get; set; } - [BackgroundDependencyLoader] - private void load() => Add(logo); + private BeatmapSetInfo importedBeatmapSet; - [SetUpSteps] - public void SetUp() + public override void SetUpSteps() { AddStep("import test beatmap", () => importedBeatmapSet = ImportBeatmapTest.LoadOszIntoOsu(game, virtualTrack: true).Result); + base.SetUpSteps(); + } - AddStep("set current beatmap", () => Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First())); - AddStep("push loader", () => Stack.Push(new EditorLoader())); - - AddUntilStep("wait for editor push", () => Stack.CurrentScreen is Editor); - AddStep("store editor", () => editor = (Editor)Stack.CurrentScreen); - AddUntilStep("wait for editor to load", () => editor.IsLoaded); + protected override void LoadEditor() + { + Beatmap.Value = beatmaps.GetWorkingBeatmap(importedBeatmapSet.Beatmaps.First()); + base.LoadEditor(); } [Test] @@ -72,11 +64,7 @@ namespace osu.Game.Tests.Visual.Editing BeatmapInfo targetDifficulty = null; PromptForSaveDialog saveDialog = null; - AddStep("remove first hitobject", () => - { - var editorBeatmap = editor.ChildrenOfType().Single(); - editorBeatmap.RemoveAt(0); - }); + AddStep("remove first hitobject", () => EditorBeatmap.RemoveAt(0)); AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo))); switchToDifficulty(() => targetDifficulty); @@ -105,11 +93,7 @@ namespace osu.Game.Tests.Visual.Editing BeatmapInfo targetDifficulty = null; PromptForSaveDialog saveDialog = null; - AddStep("remove first hitobject", () => - { - var editorBeatmap = editor.ChildrenOfType().Single(); - editorBeatmap.RemoveAt(0); - }); + AddStep("remove first hitobject", () => EditorBeatmap.RemoveAt(0)); AddStep("set target difficulty", () => targetDifficulty = importedBeatmapSet.Beatmaps.Last(beatmap => !beatmap.Equals(Beatmap.Value.BeatmapInfo))); switchToDifficulty(() => targetDifficulty); @@ -134,10 +118,10 @@ namespace osu.Game.Tests.Visual.Editing private void switchToDifficulty(Func difficulty) { - AddUntilStep("wait for menubar to load", () => editor.ChildrenOfType().Any()); + AddUntilStep("wait for menubar to load", () => Editor.ChildrenOfType().Any()); AddStep("open file menu", () => { - var menuBar = editor.ChildrenOfType().Single(); + var menuBar = Editor.ChildrenOfType().Single(); var fileMenu = menuBar.ChildrenOfType().First(); InputManager.MoveMouseTo(fileMenu); InputManager.Click(MouseButton.Left); @@ -146,7 +130,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("open difficulty menu", () => { var difficultySelector = - editor.ChildrenOfType().Single(item => item.Item.Text.Value.ToString().Contains("Change difficulty")); + Editor.ChildrenOfType().Single(item => item.Item.Text.Value.ToString().Contains("Change difficulty")); InputManager.MoveMouseTo(difficultySelector); }); AddWaitStep("wait for open", 3); @@ -154,7 +138,7 @@ namespace osu.Game.Tests.Visual.Editing AddStep("switch to target difficulty", () => { var difficultyMenuItem = - editor.ChildrenOfType() + Editor.ChildrenOfType() .Last(item => item.Item is DifficultyMenuItem difficultyItem && difficultyItem.Beatmap.Equals(difficulty.Invoke())); InputManager.MoveMouseTo(difficultyMenuItem); InputManager.Click(MouseButton.Left); From f8a681d810b2fc7c582a7941480bb11f50b8d977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 13:40:06 +0200 Subject: [PATCH 941/961] Delegate `Editor{Beatmap,Clock}` to `Editor` directly --- osu.Game/Tests/Visual/EditorTestScene.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 9fb9df39a8..3bfffeb00e 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -23,13 +23,12 @@ namespace osu.Game.Tests.Visual { public abstract class EditorTestScene : ScreenTestScene { - protected EditorBeatmap EditorBeatmap; - private TestEditorLoader editorLoader; protected TestEditor Editor => editorLoader.Editor; - protected EditorClock EditorClock { get; private set; } + protected EditorBeatmap EditorBeatmap => Editor.ChildrenOfType().Single(); + protected EditorClock EditorClock => Editor.ChildrenOfType().Single(); /// /// Whether any saves performed by the editor should be isolate (and not persist) to the underlying . @@ -66,8 +65,6 @@ namespace osu.Game.Tests.Visual AddStep("load editor", LoadEditor); AddUntilStep("wait for editor to load", () => EditorComponentsReady); - AddStep("get beatmap", () => EditorBeatmap = Editor.ChildrenOfType().Single()); - AddStep("get clock", () => EditorClock = Editor.ChildrenOfType().Single()); } protected virtual void LoadEditor() From 22fa9a303e469cc8bea35e57e187adc9cf0fd192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 13:55:48 +0200 Subject: [PATCH 942/961] Expose test helper for switching between difficulties --- .../Editing/TestSceneDifficultySwitching.cs | 32 +------------------ osu.Game/Screens/Edit/Editor.cs | 4 +-- osu.Game/Tests/Visual/EditorTestScene.cs | 2 ++ 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs index 587c37c6f5..a439555fde 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneDifficultySwitching.cs @@ -7,14 +7,11 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Testing; using osu.Game.Beatmaps; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Dialog; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; using osu.Game.Screens.Edit; -using osu.Game.Screens.Edit.Components.Menus; using osu.Game.Tests.Beatmaps.IO; -using osuTK.Input; namespace osu.Game.Tests.Visual.Editing { @@ -116,34 +113,7 @@ namespace osu.Game.Tests.Visual.Editing AddAssert("stack empty", () => Stack.CurrentScreen == null); } - private void switchToDifficulty(Func difficulty) - { - AddUntilStep("wait for menubar to load", () => Editor.ChildrenOfType().Any()); - AddStep("open file menu", () => - { - var menuBar = Editor.ChildrenOfType().Single(); - var fileMenu = menuBar.ChildrenOfType().First(); - InputManager.MoveMouseTo(fileMenu); - InputManager.Click(MouseButton.Left); - }); - - AddStep("open difficulty menu", () => - { - var difficultySelector = - Editor.ChildrenOfType().Single(item => item.Item.Text.Value.ToString().Contains("Change difficulty")); - InputManager.MoveMouseTo(difficultySelector); - }); - AddWaitStep("wait for open", 3); - - AddStep("switch to target difficulty", () => - { - var difficultyMenuItem = - Editor.ChildrenOfType() - .Last(item => item.Item is DifficultyMenuItem difficultyItem && difficultyItem.Beatmap.Equals(difficulty.Invoke())); - InputManager.MoveMouseTo(difficultyMenuItem); - InputManager.Click(MouseButton.Left); - }); - } + private void switchToDifficulty(Func difficulty) => AddStep("switch to difficulty", () => Editor.SwitchToDifficulty(difficulty.Invoke())); private void confirmEditingBeatmap(Func targetDifficulty) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 1b9a94da58..28ae7e620e 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -737,10 +737,10 @@ namespace osu.Game.Screens.Edit private DifficultyMenuItem createDifficultyMenuItem(BeatmapInfo beatmapInfo) { bool isCurrentDifficulty = playableBeatmap.BeatmapInfo.Equals(beatmapInfo); - return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, switchToDifficulty); + return new DifficultyMenuItem(beatmapInfo, isCurrentDifficulty, SwitchToDifficulty); } - private void switchToDifficulty(BeatmapInfo beatmapInfo) => loader?.ScheduleDifficultySwitch(beatmapInfo); + protected void SwitchToDifficulty(BeatmapInfo beatmapInfo) => loader?.ScheduleDifficultySwitch(beatmapInfo); private void cancelExit() => loader?.CancelPendingDifficultySwitch(); diff --git a/osu.Game/Tests/Visual/EditorTestScene.cs b/osu.Game/Tests/Visual/EditorTestScene.cs index 3bfffeb00e..1e26036116 100644 --- a/osu.Game/Tests/Visual/EditorTestScene.cs +++ b/osu.Game/Tests/Visual/EditorTestScene.cs @@ -103,6 +103,8 @@ namespace osu.Game.Tests.Visual public new void Paste() => base.Paste(); + public new void SwitchToDifficulty(BeatmapInfo beatmapInfo) => base.SwitchToDifficulty(beatmapInfo); + public new bool HasUnsavedChanges => base.HasUnsavedChanges; public TestEditor(EditorLoader loader = null) From eae5d62fa5e0c9b372cdfe4259a77cefcfe7fa7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 15:50:41 +0200 Subject: [PATCH 943/961] Store editor beatmap locally before editor exit --- .../Visual/Editing/TestSceneEditorBeatmapCreation.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index b6ae91844a..440d66ff9f 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -11,6 +11,7 @@ using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Rulesets.Osu; +using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; using osu.Game.Tests.Resources; using SharpCompress.Archives; @@ -55,6 +56,9 @@ namespace osu.Game.Tests.Visual.Editing [Test] public void TestExitWithoutSave() { + EditorBeatmap editorBeatmap = null; + + AddStep("store editor beatmap", () => editorBeatmap = EditorBeatmap); AddStep("exit without save", () => { Editor.Exit(); @@ -62,7 +66,7 @@ namespace osu.Game.Tests.Visual.Editing }); AddUntilStep("wait for exit", () => !Editor.IsCurrentScreen()); - AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == EditorBeatmap.BeatmapInfo.BeatmapSet.ID)?.DeletePending == true); + AddAssert("new beatmap not persisted", () => beatmapManager.QueryBeatmapSet(s => s.ID == editorBeatmap.BeatmapInfo.BeatmapSet.ID)?.DeletePending == true); } [Test] From 925b455330b923d6f6059337e9ccb006be270c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 16:40:52 +0200 Subject: [PATCH 944/961] Add "samples match playback rate" setting to beatmap info --- osu.Game/Beatmaps/BeatmapInfo.cs | 5 + ...11_AddSamplesMatchPlaybackRate.Designer.cs | 515 ++++++++++++++++++ ...10912144011_AddSamplesMatchPlaybackRate.cs | 23 + .../Migrations/OsuDbContextModelSnapshot.cs | 2 + 4 files changed, 545 insertions(+) create mode 100644 osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs create mode 100644 osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 3eb766a667..7dd1dd2cf4 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -93,6 +93,11 @@ namespace osu.Game.Beatmaps public bool WidescreenStoryboard { get; set; } public bool EpilepsyWarning { get; set; } + /// + /// Whether or not sound samples should change rate when playing with speed-changing mods. + /// + public bool SamplesMatchPlaybackRate { get; set; } + public CountdownType Countdown { get; set; } = CountdownType.Normal; /// diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs new file mode 100644 index 0000000000..6e53d7fae0 --- /dev/null +++ b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.Designer.cs @@ -0,0 +1,515 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using osu.Game.Database; + +namespace osu.Game.Migrations +{ + [DbContext(typeof(OsuDbContext))] + [Migration("20210912144011_AddSamplesMatchPlaybackRate")] + partial class AddSamplesMatchPlaybackRate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapDifficulty", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("ApproachRate"); + + b.Property("CircleSize"); + + b.Property("DrainRate"); + + b.Property("OverallDifficulty"); + + b.Property("SliderMultiplier"); + + b.Property("SliderTickRate"); + + b.HasKey("ID"); + + b.ToTable("BeatmapDifficulty"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("AudioLeadIn"); + + b.Property("BPM"); + + b.Property("BaseDifficultyID"); + + b.Property("BeatDivisor"); + + b.Property("BeatmapSetInfoID"); + + b.Property("Countdown"); + + b.Property("CountdownOffset"); + + b.Property("DistanceSpacing"); + + b.Property("EpilepsyWarning"); + + b.Property("GridSize"); + + b.Property("Hash"); + + b.Property("Hidden"); + + b.Property("Length"); + + b.Property("LetterboxInBreaks"); + + b.Property("MD5Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapID"); + + b.Property("Path"); + + b.Property("RulesetID"); + + b.Property("SamplesMatchPlaybackRate"); + + b.Property("SpecialStyle"); + + b.Property("StackLeniency"); + + b.Property("StarDifficulty"); + + b.Property("Status"); + + b.Property("StoredBookmarks"); + + b.Property("TimelineZoom"); + + b.Property("Version"); + + b.Property("WidescreenStoryboard"); + + b.HasKey("ID"); + + b.HasIndex("BaseDifficultyID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("Hash"); + + b.HasIndex("MD5Hash"); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("BeatmapInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapMetadata", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Artist"); + + b.Property("ArtistUnicode"); + + b.Property("AudioFile"); + + b.Property("AuthorID") + .HasColumnName("AuthorID"); + + b.Property("AuthorString") + .HasColumnName("Author"); + + b.Property("BackgroundFile"); + + b.Property("PreviewTime"); + + b.Property("Source"); + + b.Property("Tags"); + + b.Property("Title"); + + b.Property("TitleUnicode"); + + b.HasKey("ID"); + + b.ToTable("BeatmapMetadata"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("BeatmapSetInfoID"); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.HasKey("ID"); + + b.HasIndex("BeatmapSetInfoID"); + + b.HasIndex("FileInfoID"); + + b.ToTable("BeatmapSetFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("DateAdded"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MetadataID"); + + b.Property("OnlineBeatmapSetID"); + + b.Property("Protected"); + + b.Property("Status"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("MetadataID"); + + b.HasIndex("OnlineBeatmapSetID") + .IsUnique(); + + b.ToTable("BeatmapSetInfo"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Key") + .HasColumnName("Key"); + + b.Property("RulesetID"); + + b.Property("SkinInfoID"); + + b.Property("StringValue") + .HasColumnName("Value"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("SkinInfoID"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("Settings"); + }); + + modelBuilder.Entity("osu.Game.IO.FileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Hash"); + + b.Property("ReferenceCount"); + + b.HasKey("ID"); + + b.HasIndex("Hash") + .IsUnique(); + + b.HasIndex("ReferenceCount"); + + b.ToTable("FileInfo"); + }); + + modelBuilder.Entity("osu.Game.Input.Bindings.DatabasedKeyBinding", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("IntAction") + .HasColumnName("Action"); + + b.Property("KeysString") + .HasColumnName("Keys"); + + b.Property("RulesetID"); + + b.Property("Variant"); + + b.HasKey("ID"); + + b.HasIndex("IntAction"); + + b.HasIndex("RulesetID", "Variant"); + + b.ToTable("KeyBinding"); + }); + + modelBuilder.Entity("osu.Game.Rulesets.RulesetInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Available"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.Property("ShortName"); + + b.HasKey("ID"); + + b.HasIndex("Available"); + + b.HasIndex("ShortName") + .IsUnique(); + + b.ToTable("RulesetInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("ScoreInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("ScoreInfoID"); + + b.ToTable("ScoreFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Accuracy") + .HasColumnType("DECIMAL(1,4)"); + + b.Property("BeatmapInfoID"); + + b.Property("Combo"); + + b.Property("Date"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("MaxCombo"); + + b.Property("ModsJson") + .HasColumnName("Mods"); + + b.Property("OnlineScoreID"); + + b.Property("PP"); + + b.Property("Rank"); + + b.Property("RulesetID"); + + b.Property("StatisticsJson") + .HasColumnName("Statistics"); + + b.Property("TotalScore"); + + b.Property("UserID") + .HasColumnName("UserID"); + + b.Property("UserString") + .HasColumnName("User"); + + b.HasKey("ID"); + + b.HasIndex("BeatmapInfoID"); + + b.HasIndex("OnlineScoreID") + .IsUnique(); + + b.HasIndex("RulesetID"); + + b.ToTable("ScoreInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("FileInfoID"); + + b.Property("Filename") + .IsRequired(); + + b.Property("SkinInfoID"); + + b.HasKey("ID"); + + b.HasIndex("FileInfoID"); + + b.HasIndex("SkinInfoID"); + + b.ToTable("SkinFileInfo"); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinInfo", b => + { + b.Property("ID") + .ValueGeneratedOnAdd(); + + b.Property("Creator"); + + b.Property("DeletePending"); + + b.Property("Hash"); + + b.Property("InstantiationInfo"); + + b.Property("Name"); + + b.HasKey("ID"); + + b.HasIndex("DeletePending"); + + b.HasIndex("Hash") + .IsUnique(); + + b.ToTable("SkinInfo"); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapDifficulty", "BaseDifficulty") + .WithMany() + .HasForeignKey("BaseDifficultyID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo", "BeatmapSet") + .WithMany("Beatmaps") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("Beatmaps") + .HasForeignKey("MetadataID"); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetFileInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapSetInfo") + .WithMany("Files") + .HasForeignKey("BeatmapSetInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Beatmaps.BeatmapSetInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapMetadata", "Metadata") + .WithMany("BeatmapSets") + .HasForeignKey("MetadataID"); + }); + + modelBuilder.Entity("osu.Game.Configuration.DatabasedSetting", b => + { + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Settings") + .HasForeignKey("SkinInfoID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Scoring.ScoreInfo") + .WithMany("Files") + .HasForeignKey("ScoreInfoID"); + }); + + modelBuilder.Entity("osu.Game.Scoring.ScoreInfo", b => + { + b.HasOne("osu.Game.Beatmaps.BeatmapInfo", "Beatmap") + .WithMany("Scores") + .HasForeignKey("BeatmapInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Rulesets.RulesetInfo", "Ruleset") + .WithMany() + .HasForeignKey("RulesetID") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("osu.Game.Skinning.SkinFileInfo", b => + { + b.HasOne("osu.Game.IO.FileInfo", "FileInfo") + .WithMany() + .HasForeignKey("FileInfoID") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("osu.Game.Skinning.SkinInfo") + .WithMany("Files") + .HasForeignKey("SkinInfoID") + .OnDelete(DeleteBehavior.Cascade); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs new file mode 100644 index 0000000000..bf3f855d5f --- /dev/null +++ b/osu.Game/Migrations/20210912144011_AddSamplesMatchPlaybackRate.cs @@ -0,0 +1,23 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace osu.Game.Migrations +{ + public partial class AddSamplesMatchPlaybackRate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "SamplesMatchPlaybackRate", + table: "BeatmapInfo", + nullable: false, + defaultValue: false); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "SamplesMatchPlaybackRate", + table: "BeatmapInfo"); + } + } +} diff --git a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs index 470907ada6..036c26cb0a 100644 --- a/osu.Game/Migrations/OsuDbContextModelSnapshot.cs +++ b/osu.Game/Migrations/OsuDbContextModelSnapshot.cs @@ -81,6 +81,8 @@ namespace osu.Game.Migrations b.Property("RulesetID"); + b.Property("SamplesMatchPlaybackRate"); + b.Property("SpecialStyle"); b.Property("StackLeniency"); From cd181452be90a7fc96a888bfac732fca7e921615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 16:45:27 +0200 Subject: [PATCH 945/961] Add decoding support for `SamplesMatchPlaybackRate` --- osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs | 1 + osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs index 8560a36fb4..a4bf8c92e3 100644 --- a/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs +++ b/osu.Game.Tests/Beatmaps/Formats/LegacyBeatmapDecoderTest.cs @@ -64,6 +64,7 @@ namespace osu.Game.Tests.Beatmaps.Formats Assert.IsFalse(beatmapInfo.LetterboxInBreaks); Assert.IsFalse(beatmapInfo.SpecialStyle); Assert.IsFalse(beatmapInfo.WidescreenStoryboard); + Assert.IsFalse(beatmapInfo.SamplesMatchPlaybackRate); Assert.AreEqual(CountdownType.None, beatmapInfo.Countdown); Assert.AreEqual(0, beatmapInfo.CountdownOffset); } diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index accefb2583..4b5eaafa4a 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -180,6 +180,10 @@ namespace osu.Game.Beatmaps.Formats beatmap.BeatmapInfo.EpilepsyWarning = Parsing.ParseInt(pair.Value) == 1; break; + case @"SamplesMatchPlaybackRate": + beatmap.BeatmapInfo.SamplesMatchPlaybackRate = Parsing.ParseInt(pair.Value) == 1; + break; + case @"Countdown": beatmap.BeatmapInfo.Countdown = (CountdownType)Enum.Parse(typeof(CountdownType), pair.Value); break; From af7c2b93e63b78d3a119ec8580432b02b7211765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 16:47:38 +0200 Subject: [PATCH 946/961] Add encoding support for `SamplesMatchPlaybackRate` --- osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs index 75d9a56f3e..aef13b8872 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapEncoder.cs @@ -105,8 +105,8 @@ namespace osu.Game.Beatmaps.Formats if (beatmap.BeatmapInfo.RulesetID == 3) writer.WriteLine(FormattableString.Invariant($"SpecialStyle: {(beatmap.BeatmapInfo.SpecialStyle ? '1' : '0')}")); writer.WriteLine(FormattableString.Invariant($"WidescreenStoryboard: {(beatmap.BeatmapInfo.WidescreenStoryboard ? '1' : '0')}")); - // if (b.SamplesMatchPlaybackRate) - // writer.WriteLine(@"SamplesMatchPlaybackRate: 1"); + if (beatmap.BeatmapInfo.SamplesMatchPlaybackRate) + writer.WriteLine(@"SamplesMatchPlaybackRate: 1"); } private void handleEditor(TextWriter writer) From 345cde251db4b35d0308083a37255dc7bff24c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 16:54:17 +0200 Subject: [PATCH 947/961] Add "samples match playback rate" to editor setup screen --- osu.Game/Screens/Edit/Setup/DesignSection.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Screens/Edit/Setup/DesignSection.cs b/osu.Game/Screens/Edit/Setup/DesignSection.cs index 90f95a668e..d5d93db050 100644 --- a/osu.Game/Screens/Edit/Setup/DesignSection.cs +++ b/osu.Game/Screens/Edit/Setup/DesignSection.cs @@ -25,6 +25,7 @@ namespace osu.Game.Screens.Edit.Setup private LabelledSwitchButton widescreenSupport; private LabelledSwitchButton epilepsyWarning; private LabelledSwitchButton letterboxDuringBreaks; + private LabelledSwitchButton samplesMatchPlaybackRate; public override LocalisableString Title => "Design"; @@ -79,6 +80,12 @@ namespace osu.Game.Screens.Edit.Setup Label = "Letterbox during breaks", Description = "Adds horizontal letterboxing to give a cinematic look during breaks.", Current = { Value = Beatmap.BeatmapInfo.LetterboxInBreaks } + }, + samplesMatchPlaybackRate = new LabelledSwitchButton + { + Label = "Samples match playback rate", + Description = "When enabled, all samples will speed up or slow down when rate-changing mods are enabled.", + Current = { Value = Beatmap.BeatmapInfo.SamplesMatchPlaybackRate } } }; } @@ -96,6 +103,7 @@ namespace osu.Game.Screens.Edit.Setup widescreenSupport.Current.BindValueChanged(_ => updateBeatmap()); epilepsyWarning.Current.BindValueChanged(_ => updateBeatmap()); letterboxDuringBreaks.Current.BindValueChanged(_ => updateBeatmap()); + samplesMatchPlaybackRate.Current.BindValueChanged(_ => updateBeatmap()); } private void updateCountdownSettingsVisibility() => CountdownSettings.FadeTo(EnableCountdown.Current.Value ? 1 : 0); @@ -115,6 +123,7 @@ namespace osu.Game.Screens.Edit.Setup Beatmap.BeatmapInfo.WidescreenStoryboard = widescreenSupport.Current.Value; Beatmap.BeatmapInfo.EpilepsyWarning = epilepsyWarning.Current.Value; Beatmap.BeatmapInfo.LetterboxInBreaks = letterboxDuringBreaks.Current.Value; + Beatmap.BeatmapInfo.SamplesMatchPlaybackRate = samplesMatchPlaybackRate.Current.Value; } } } From 1be8cb452f87afd29db37fec2b8b68e5fb296f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 16:57:21 +0200 Subject: [PATCH 948/961] Make new beatmaps' samples match playback rate by default --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 27aa874dc9..bd85017d58 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -129,6 +129,7 @@ namespace osu.Game.Beatmaps Ruleset = ruleset, Metadata = metadata, WidescreenStoryboard = true, + SamplesMatchPlaybackRate = true, } } }; From fdd48c3e71cf997e3acfe626a9f0ac40f7281d61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 17:41:50 +0200 Subject: [PATCH 949/961] Refactor note colouring test scene --- .../TestSceneTimingBasedNoteColouring.cs | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs index e14ad92842..8405b14e1f 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Mania.Objects; using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Framework.Bindables; +using osu.Framework.Testing; namespace osu.Game.Rulesets.Mania.Tests { @@ -22,14 +23,42 @@ namespace osu.Game.Rulesets.Mania.Tests [Resolved] private RulesetConfigCache configCache { get; set; } - private readonly Bindable configTimingBasedNoteColouring = new Bindable(); + private Bindable configTimingBasedNoteColouring; - protected override void LoadComplete() + private ManualClock clock; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("setup hierarchy", () => Child = new Container + { + Clock = new FramedClock(clock = new ManualClock()), + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Children = new[] + { + Ruleset.Value.CreateInstance().CreateDrawableRulesetWith(createTestBeatmap()) + } + }); + AddStep("retrieve config bindable", () => + { + var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance()); + configTimingBasedNoteColouring = config.GetBindable(ManiaRulesetSetting.TimingBasedNoteColouring); + }); + } + + [Test] + public void TestSimple() + { + AddStep("enable", () => configTimingBasedNoteColouring.Value = true); + AddStep("disable", () => configTimingBasedNoteColouring.Value = false); + } + + private ManiaBeatmap createTestBeatmap() { const double beat_length = 500; - var ruleset = new ManiaRuleset(); - var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 1 }) { HitObjects = @@ -45,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Tests new Note { StartTime = beat_length } }, ControlPointInfo = new ControlPointInfo(), - BeatmapInfo = { Ruleset = ruleset.RulesetInfo }, + BeatmapInfo = { Ruleset = Ruleset.Value }, }; foreach (var note in beatmap.HitObjects) @@ -57,24 +86,7 @@ namespace osu.Game.Rulesets.Mania.Tests { BeatLength = beat_length }); - - Child = new Container - { - Clock = new FramedClock(new ManualClock()), - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Children = new[] - { - ruleset.CreateDrawableRulesetWith(beatmap) - } - }; - - var config = (ManiaRulesetConfigManager)configCache.GetConfigFor(Ruleset.Value.CreateInstance()); - config.BindWith(ManiaRulesetSetting.TimingBasedNoteColouring, configTimingBasedNoteColouring); - - AddStep("Enable", () => configTimingBasedNoteColouring.Value = true); - AddStep("Disable", () => configTimingBasedNoteColouring.Value = false); + return beatmap; } } } From 1edf608260c350ffe3164ea99be484ef15609fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 17:48:08 +0200 Subject: [PATCH 950/961] Add failing test case --- .../TestSceneTimingBasedNoteColouring.cs | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs index 8405b14e1f..449a6ff23d 100644 --- a/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.cs +++ b/osu.Game.Rulesets.Mania.Tests/TestSceneTimingBasedNoteColouring.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 NUnit.Framework; using osu.Framework.Graphics; using osu.Framework.Allocation; @@ -14,6 +15,9 @@ using osu.Game.Rulesets.Mania.Beatmaps; using osu.Game.Rulesets.Mania.Configuration; using osu.Framework.Bindables; using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Rulesets.Mania.Objects.Drawables; +using osu.Game.Rulesets.Mania.UI; namespace osu.Game.Rulesets.Mania.Tests { @@ -26,6 +30,7 @@ namespace osu.Game.Rulesets.Mania.Tests private Bindable configTimingBasedNoteColouring; private ManualClock clock; + private DrawableManiaRuleset drawableRuleset; [SetUpSteps] public void SetUpSteps() @@ -38,7 +43,7 @@ namespace osu.Game.Rulesets.Mania.Tests Origin = Anchor.Centre, Children = new[] { - Ruleset.Value.CreateInstance().CreateDrawableRulesetWith(createTestBeatmap()) + drawableRuleset = (DrawableManiaRuleset)Ruleset.Value.CreateInstance().CreateDrawableRulesetWith(createTestBeatmap()) } }); AddStep("retrieve config bindable", () => @@ -55,6 +60,28 @@ namespace osu.Game.Rulesets.Mania.Tests AddStep("disable", () => configTimingBasedNoteColouring.Value = false); } + [Test] + public void TestToggleOffScreen() + { + AddStep("enable", () => configTimingBasedNoteColouring.Value = true); + + seekTo(10000); + AddStep("disable", () => configTimingBasedNoteColouring.Value = false); + seekTo(0); + AddAssert("all notes not coloured", () => this.ChildrenOfType().All(note => note.Colour == Colour4.White)); + + seekTo(10000); + AddStep("enable again", () => configTimingBasedNoteColouring.Value = true); + seekTo(0); + AddAssert("some notes coloured", () => this.ChildrenOfType().Any(note => note.Colour != Colour4.White)); + } + + private void seekTo(double time) + { + AddStep($"seek to {time}", () => clock.CurrentTime = time); + AddUntilStep("wait for seek", () => Precision.AlmostEquals(drawableRuleset.FrameStableClock.CurrentTime, time, 1)); + } + private ManiaBeatmap createTestBeatmap() { const double beat_length = 500; From 922fa96d411d6119a24020243785d8d912d8ea1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 12 Sep 2021 17:51:15 +0200 Subject: [PATCH 951/961] Fix notes not updating snap colour on application --- osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs index 33d872dfb6..d53c28868d 100644 --- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs +++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableNote.cs @@ -66,6 +66,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables StartTimeBindable.BindValueChanged(_ => updateSnapColour(), true); } + protected override void OnApply() + { + base.OnApply(); + updateSnapColour(); + } + protected override void OnDirectionChanged(ValueChangedEvent e) { base.OnDirectionChanged(e); From 5969e2b8529e7917f86770bfe1d4e692e6d58751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 13 Sep 2021 00:13:07 +0200 Subject: [PATCH 952/961] Add TODO comment about lack of in-gameplay support --- osu.Game/Beatmaps/BeatmapInfo.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs index 7dd1dd2cf4..8cb5da8083 100644 --- a/osu.Game/Beatmaps/BeatmapInfo.cs +++ b/osu.Game/Beatmaps/BeatmapInfo.cs @@ -95,6 +95,7 @@ namespace osu.Game.Beatmaps /// /// Whether or not sound samples should change rate when playing with speed-changing mods. + /// TODO: only read/write supported for now, requires implementation in gameplay. /// public bool SamplesMatchPlaybackRate { get; set; } From 7fe0eefb789a52d47a19286db53dacc4a2b2eaaa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 14:12:18 +0900 Subject: [PATCH 953/961] Add inline comment regarding team switch sample logic Feels a bit convoluted without this. Don't really have a better suggestion for now so a comment will do. --- .../Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs index 915cf30963..833fbd6605 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Participants/TeamDisplay.cs @@ -105,6 +105,8 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Participants if (newTeam == displayedTeam) return; + // only play the sample if an already valid team changes to another valid team. + // this avoids playing a sound for each user if the match type is changed to/from a team mode. if (newTeam != null && displayedTeam != null) sampleTeamSwap?.Play(); From 684c39dad04a87d0cbaa7cbb341b9bb5133fec9f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 14:12:37 +0900 Subject: [PATCH 954/961] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 7378450c38..d4331a5e65 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index d80dd075ee..941656bb70 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -37,7 +37,7 @@ - + diff --git a/osu.iOS.props b/osu.iOS.props index 8ce757974e..73e0030114 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 52c69d2f2290815ee5406079423849ed6eaf6961 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 14:17:45 +0900 Subject: [PATCH 955/961] Adjust value to not be full width (but allow for more accommodations with localised versions) --- .../Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs index 2e49671669..fae0318359 100644 --- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs +++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input { Text = InputSettingsStrings.ResetSectionButton; RelativeSizeAxes = Axes.X; - Width = Content.Width; + Width = 0.8f; Anchor = Anchor.TopCentre; Origin = Anchor.TopCentre; Margin = new MarginPadding { Top = 15 }; From caf7ef6519bb928f44769fbddbb862aa1fd40809 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 15:00:33 +0900 Subject: [PATCH 956/961] Add missing screen level mod application settings for some screens Closes #7480. But based on discussion in there this solution may change. --- .../Settings/Sections/Maintenance/DirectorySelectScreen.cs | 2 ++ osu.Game/Screens/Import/FileImportScreen.cs | 2 ++ osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs index e509cac2f1..1d67968ab1 100644 --- a/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/DirectorySelectScreen.cs @@ -24,6 +24,8 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance private OsuDirectorySelector directorySelector; + public override bool AllowTrackAdjustments => false; + /// /// Text to display in the header to inform the user of what they are selecting. /// diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index 7e1d55b3e2..606174193d 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -23,6 +23,8 @@ namespace osu.Game.Screens.Import { public override bool HideOverlaysOnEnter => true; + public override bool AllowTrackAdjustments => false; + private OsuFileSelector fileSelector; private Container contentContainer; private TextFlowContainer currentFileText; diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs index fc20b21b60..62bfd2cfed 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlayScreen.cs @@ -24,6 +24,8 @@ namespace osu.Game.Screens.OnlinePlay [Cached] protected readonly OverlayColourProvider ColourProvider = new OverlayColourProvider(OverlayColourScheme.Plum); + public override bool AllowTrackAdjustments => false; + public override bool CursorVisible => (screenStack?.CurrentScreen as IOnlinePlaySubScreen)?.CursorVisible ?? true; // this is required due to PlayerLoader eventually being pushed to the main stack From 0f5ed81a7a51467b1c10556856bc602ecda0622a Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Mon, 13 Sep 2021 13:31:13 +0300 Subject: [PATCH 957/961] Fix dimmed checked nub artifact This adds transition that extends nub's border to fill it. Fill fade can be removed, but combined effect looks nicer imo, and the fill is still needed because if removed, border becomes invisible for some reason. --- osu.Game/Graphics/UserInterface/Nub.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 664f32b083..4e5c78be77 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -47,6 +47,7 @@ namespace osu.Game.Graphics.UserInterface }; Current.ValueChanged += filled => fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint); + Current.ValueChanged += filled => this.TransformTo(nameof(BorderThickness), filled.NewValue ? 7 : border_width, 200, Easing.OutQuint); } [BackgroundDependencyLoader] From 4d2373ffb9e8216394936b31a92b9fd72c7788e0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 13 Sep 2021 20:08:46 +0900 Subject: [PATCH 958/961] Combine similar value changed calls --- osu.Game/Graphics/UserInterface/Nub.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index 4e5c78be77..bd3b2e1715 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -46,8 +46,11 @@ namespace osu.Game.Graphics.UserInterface }, }; - Current.ValueChanged += filled => fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint); - Current.ValueChanged += filled => this.TransformTo(nameof(BorderThickness), filled.NewValue ? 7 : border_width, 200, Easing.OutQuint); + Current.ValueChanged += filled => + { + fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint); + this.TransformTo(nameof(BorderThickness), filled.NewValue ? 7 : border_width, 200, Easing.OutQuint); + }; } [BackgroundDependencyLoader] From 9c1fc2ec6536e5b1ac363d8717e224560609f370 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Mon, 13 Sep 2021 14:19:33 +0300 Subject: [PATCH 959/961] Tweak filled nub border width value --- osu.Game/Graphics/UserInterface/Nub.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index bd3b2e1715..6807d007bb 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface Current.ValueChanged += filled => { fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint); - this.TransformTo(nameof(BorderThickness), filled.NewValue ? 7 : border_width, 200, Easing.OutQuint); + this.TransformTo(nameof(BorderThickness), filled.NewValue ? 8.5f : border_width, 200, Easing.OutQuint); }; } From 7267602b951db6c708d379331bf7173528615c24 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Mon, 13 Sep 2021 17:14:39 +0300 Subject: [PATCH 960/961] Fix icon orientation for horizontal bar hit error meter --- .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 20 +++++++++++++------ osu.Game/Skinning/LegacySkin.cs | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 89f61785e8..a557e0acd7 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -33,6 +33,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters private const float chevron_size = 8; private SpriteIcon arrow; + private SpriteIcon iconEarly; + private SpriteIcon iconLate; private Container colourBarsEarly; private Container colourBarsLate; @@ -97,25 +99,21 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters RelativeSizeAxes = Axes.Both, Height = 0.5f, }, - new SpriteIcon + iconEarly = new SpriteIcon { Y = -10, Size = new Vector2(10), Icon = FontAwesome.Solid.ShippingFast, Anchor = Anchor.TopCentre, Origin = Anchor.Centre, - // undo any layout rotation to display the icon the correct orientation - Rotation = -Rotation, }, - new SpriteIcon + iconLate = new SpriteIcon { Y = 10, Size = new Vector2(10), Icon = FontAwesome.Solid.Bicycle, Anchor = Anchor.BottomCentre, Origin = Anchor.Centre, - // undo any layout rotation to display the icon the correct orientation - Rotation = -Rotation, } } }, @@ -130,6 +128,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; createColourBars(colours); + OrientIcons(); } protected override void LoadComplete() @@ -143,6 +142,15 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters arrow.Delay(200).FadeInFromZero(600); } + /// + /// Method to undo any layout rotation to display icons in the correct orientation. + /// + public void OrientIcons() + { + iconEarly.Rotation = -Rotation; + iconLate.Rotation = -Rotation; + } + private void createColourBars(OsuColour colours) { var windows = HitWindows.GetAllAvailableWindows().ToArray(); diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index b09620411b..41f5b7ae46 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -376,6 +376,7 @@ namespace osu.Game.Skinning hitError.Anchor = Anchor.BottomCentre; hitError.Origin = Anchor.CentreLeft; hitError.Rotation = -90; + if (hitError is BarHitErrorMeter barHitError) barHitError.OrientIcons(); } if (songProgress != null) From 3c75094f4350181f3e1e9a5dc070231a94906280 Mon Sep 17 00:00:00 2001 From: AbstractQbit <38468635+AbstractQbit@users.noreply.github.com> Date: Mon, 13 Sep 2021 19:41:55 +0300 Subject: [PATCH 961/961] Move `BarHitErrorMeter`'s icon reorintation to `Update()` --- .../Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs | 9 ++++----- osu.Game/Skinning/LegacySkin.cs | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index a557e0acd7..7562df5a3b 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -128,7 +128,6 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters }; createColourBars(colours); - OrientIcons(); } protected override void LoadComplete() @@ -142,11 +141,11 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters arrow.Delay(200).FadeInFromZero(600); } - /// - /// Method to undo any layout rotation to display icons in the correct orientation. - /// - public void OrientIcons() + protected override void Update() { + base.Update(); + + // undo any layout rotation to display icons in the correct orientation iconEarly.Rotation = -Rotation; iconLate.Rotation = -Rotation; } diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs index 41f5b7ae46..b09620411b 100644 --- a/osu.Game/Skinning/LegacySkin.cs +++ b/osu.Game/Skinning/LegacySkin.cs @@ -376,7 +376,6 @@ namespace osu.Game.Skinning hitError.Anchor = Anchor.BottomCentre; hitError.Origin = Anchor.CentreLeft; hitError.Rotation = -90; - if (hitError is BarHitErrorMeter barHitError) barHitError.OrientIcons(); } if (songProgress != null)