From d467dd57472ebc001ee28eb6f01d6b468702e735 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 29 Jul 2019 06:51:44 +0300 Subject: [PATCH 01/20] Add simple implementation of in-game leaderboard --- osu.Game/Screens/Play/InGameLeaderboard.cs | 42 ++++ osu.Game/Screens/Play/InGameScoreContainer.cs | 206 ++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 osu.Game/Screens/Play/InGameLeaderboard.cs create mode 100644 osu.Game/Screens/Play/InGameScoreContainer.cs diff --git a/osu.Game/Screens/Play/InGameLeaderboard.cs b/osu.Game/Screens/Play/InGameLeaderboard.cs new file mode 100644 index 0000000000..c8f5cf5fd7 --- /dev/null +++ b/osu.Game/Screens/Play/InGameLeaderboard.cs @@ -0,0 +1,42 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Users; + +namespace osu.Game.Screens.Play +{ + public class InGameLeaderboard : CompositeDrawable + { + protected readonly InGameScoreContainer ScoresContainer; + + public readonly BindableDouble PlayerCurrentScore = new BindableDouble(); + + private bool playerItemCreated; + private User playerUser; + + public User PlayerUser + { + get => playerUser; + set + { + playerUser = value; + + if (playerItemCreated) + return; + + ScoresContainer.AddRealTimePlayer(PlayerCurrentScore, playerUser); + playerItemCreated = true; + } + } + + public InGameLeaderboard() + { + AutoSizeAxes = Axes.Y; + + InternalChild = ScoresContainer = new InGameScoreContainer(); + } + } +} diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs new file mode 100644 index 0000000000..eb4a0a2f38 --- /dev/null +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -0,0 +1,206 @@ +// 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 Humanizer; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Scoring; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Screens.Play +{ + public class InGameScoreContainer : FillFlowContainer + { + /// + /// Whether to declare a new position for un-positioned players. + /// Must be disabled for online leaderboards with top 50 scores only. + /// + public bool DeclareNewPosition = true; + + public InGameScoreContainer() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(2.5f); + LayoutDuration = 500; + LayoutEasing = Easing.OutQuint; + } + + public void AddRealTimePlayer(BindableDouble currentScore, User user = null) + { + if (currentScore == null) + return; + + var scoreItem = addScore(currentScore.Value, user); + currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; + } + + public void AddScore(ScoreInfo score, int? position = null) + { + if (score != null) + addScore(score.TotalScore, score.User, position); + } + + private int maxPosition => this.Where(i => i.ScorePosition.HasValue).Max(i => i.ScorePosition) ?? 0; + + private InGameScoreItem addScore(double totalScore, User user = null, int? position = null) + { + var scoreItem = new InGameScoreItem + { + User = user, + TotalScore = totalScore, + ScorePosition = position, + OnScoreChange = updateScores, + }; + + Add(scoreItem); + SetLayoutPosition(scoreItem, position ?? maxPosition + 1); + + updateScores(); + + return scoreItem; + } + + private void updateScores() + { + var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); + var orderedPositions = this.OrderByDescending(i => i.ScorePosition.HasValue).ThenBy(i => i.ScorePosition).Select(i => i.ScorePosition).ToList(); + + for (int i = 0; i < Count; i++) + { + int newPosition = orderedPositions[i] ?? maxPosition + 1; + + SetLayoutPosition(orderedByScore[i], newPosition); + orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; + } + } + } + + public class InGameScoreItem : CompositeDrawable + { + private readonly OsuSpriteText positionText, positionSymbol, userString; + private readonly GlowingSpriteText scoreText; + + public Action OnScoreChange; + + private int? scorePosition; + + public int? ScorePosition + { + get => scorePosition; + set + { + scorePosition = value; + + if (scorePosition.HasValue) + positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}"; + + positionText.FadeTo(scorePosition.HasValue ? 1 : 0, 100); + positionSymbol.FadeTo(scorePosition.HasValue ? 1 : 0, 100); + } + } + + private double totalScore; + + public double TotalScore + { + get => totalScore; + set + { + totalScore = value; + scoreText.Text = totalScore.ToString("N0"); + + OnScoreChange?.Invoke(); + } + } + + private User user; + + public User User + { + get => user; + set + { + user = value; + userString.Text = user?.Username; + } + } + + public InGameScoreItem() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + InternalChild = new Container + { + Masking = true, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Right = 2.5f }, + Spacing = new Vector2(2.5f), + Children = new[] + { + positionText = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold), + }, + positionSymbol = new OsuSpriteText + { + Alpha = 0, + Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold), + Text = ">", + }, + } + }, + new FillFlowContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Left = 2.5f }, + Spacing = new Vector2(2.5f), + Children = new Drawable[] + { + userString = new OsuSpriteText + { + Size = new Vector2(80, 16), + Font = OsuFont.GetFont(size: 14, weight: FontWeight.Bold, italics: true), + }, + scoreText = new GlowingSpriteText + { + GlowColour = OsuColour.FromHex(@"83ccfa"), + Font = OsuFont.Numeric.With(size: 14), + } + } + }, + }, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + positionText.Colour = colours.YellowLight; + positionSymbol.Colour = colours.Yellow; + } + } +} From 6233dc22e0b76bda53722e0aca270d67e0e39c8c Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Mon, 29 Jul 2019 06:52:42 +0300 Subject: [PATCH 02/20] Add simple tests for current implementation --- .../Gameplay/TestSceneInGameLeaderboard.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs new file mode 100644 index 0000000000..36ed8f9b4c --- /dev/null +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -0,0 +1,79 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Screens.Play; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Tests.Visual.Gameplay +{ + [TestFixture] + public class TestSceneInGameLeaderboard : OsuTestScene + { + public override IReadOnlyList RequiredTypes => new[] + { + typeof(InGameLeaderboard), + typeof(InGameScoreContainer), + }; + + private readonly TestInGameLeaderboard leaderboard; + private readonly BindableDouble playerScore; + + public TestSceneInGameLeaderboard() + { + Add(leaderboard = new TestInGameLeaderboard + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Scale = new Vector2(2), + RelativeSizeAxes = Axes.X, + PlayerCurrentScore = { BindTarget = playerScore = new BindableDouble(1222333) } + }); + + AddStep("add player user", () => leaderboard.PlayerUser = new User { Username = "You" }); + AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); + } + + [Test] + public void TestPlayerScore() + { + var player2Score = new BindableDouble(1234567); + var player3Score = new BindableDouble(1111111); + + AddStep("add player 2", () => leaderboard.AddDummyPlayer(player2Score, "Player 2")); + AddStep("add player 3", () => leaderboard.AddDummyPlayer(player3Score, "Player 3")); + + AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); + AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); + AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); + + AddStep("set score above player 3", () => player2Score.Value = playerScore.Value - 500); + AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); + AddAssert("is player 2 position #2", () => leaderboard.CheckPositionByUsername("Player 2", 2)); + AddAssert("is player 3 position #3", () => leaderboard.CheckPositionByUsername("Player 3", 3)); + + AddStep("set score below players", () => player2Score.Value = playerScore.Value - 123456); + AddAssert("is player position #1", () => leaderboard.CheckPositionByUsername("You", 1)); + AddAssert("is player 3 position #2", () => leaderboard.CheckPositionByUsername("Player 3", 2)); + AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); + } + + private class TestInGameLeaderboard : InGameLeaderboard + { + public bool CheckPositionByUsername(string username, int? estimatedPosition) + { + var scoreItem = ScoresContainer.Where(i => i.User.Username == username).FirstOrDefault(); + + return scoreItem != null && scoreItem.ScorePosition == estimatedPosition; + } + + public void AddDummyPlayer(BindableDouble currentScore, string username) => ScoresContainer.AddRealTimePlayer(currentScore, new User { Username = username }); + } + } +} From 4874746525615cb5aaffbe6195d8038b7766543b Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 30 Jul 2019 12:32:12 +0300 Subject: [PATCH 03/20] Add OnScoreChange event For use in scrolling system on a later PR --- osu.Game/Screens/Play/InGameScoreContainer.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index eb4a0a2f38..985e867510 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -18,6 +18,12 @@ namespace osu.Game.Screens.Play { public class InGameScoreContainer : FillFlowContainer { + /// + /// Called once an item's score has changed. + /// Useful for doing calculations on what score to show or hide next. (scrolling system) + /// + public event Action OnScoreChange; + /// /// Whether to declare a new position for un-positioned players. /// Must be disabled for online leaderboards with top 50 scores only. @@ -64,12 +70,12 @@ namespace osu.Game.Screens.Play Add(scoreItem); SetLayoutPosition(scoreItem, position ?? maxPosition + 1); - updateScores(); + reorderPositions(); return scoreItem; } - private void updateScores() + private void reorderPositions() { var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); var orderedPositions = this.OrderByDescending(i => i.ScorePosition.HasValue).ThenBy(i => i.ScorePosition).Select(i => i.ScorePosition).ToList(); @@ -82,6 +88,13 @@ namespace osu.Game.Screens.Play orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; } } + + private void updateScores() + { + reorderPositions(); + + OnScoreChange?.Invoke(); + } } public class InGameScoreItem : CompositeDrawable From 32498d5d5088f4b009eec5d7304ea10f96dbb515 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 30 Jul 2019 12:35:49 +0300 Subject: [PATCH 04/20] Add xmldocs and return score items. Return for usage in later PR --- osu.Game/Screens/Play/InGameScoreContainer.cs | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index 985e867510..0ebf475e18 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -40,20 +40,30 @@ namespace osu.Game.Screens.Play LayoutEasing = Easing.OutQuint; } - public void AddRealTimePlayer(BindableDouble currentScore, User user = null) + /// + /// Adds a real-time player score item whose score is updated via a . + /// + /// The bindable current score of the player. + /// The player user. + /// Returns the drawable score item of that player. + public InGameScoreItem AddRealTimePlayer(BindableDouble currentScore, User user = null) { if (currentScore == null) - return; + return null; var scoreItem = addScore(currentScore.Value, user); currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; + + return scoreItem; } - public void AddScore(ScoreInfo score, int? position = null) - { - if (score != null) - addScore(score.TotalScore, score.User, position); - } + /// + /// Adds a score item based off a with an initial position. + /// + /// The score info to use for this item. + /// The initial position of this item. + /// Returns the drawable score item of that player. + public InGameScoreItem AddScore(ScoreInfo score, int? position = null) => score != null ? addScore(score.TotalScore, score.User, position) : null; private int maxPosition => this.Where(i => i.ScorePosition.HasValue).Max(i => i.ScorePosition) ?? 0; From 77aa3a9fe56437c3b4aca91b12e87ee5880a8b39 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Tue, 30 Jul 2019 12:37:01 +0300 Subject: [PATCH 05/20] Clear previous score items on SetUp --- osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 36ed8f9b4c..4a861428de 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -40,6 +40,9 @@ namespace osu.Game.Tests.Visual.Gameplay AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } + [SetUp] + public void SetUp() => leaderboard.ClearScores(); + [Test] public void TestPlayerScore() { @@ -66,6 +69,8 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestInGameLeaderboard : InGameLeaderboard { + public void ClearScores() => ScoresContainer.RemoveAll(s => s.User.Username != PlayerUser.Username); + public bool CheckPositionByUsername(string username, int? estimatedPosition) { var scoreItem = ScoresContainer.Where(i => i.User.Username == username).FirstOrDefault(); From 7675c679db84f0fa422b6f9034407527f36484af Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Wed, 31 Jul 2019 16:09:40 +0300 Subject: [PATCH 06/20] Fix reordering not declaring new position properly Small bug fix --- osu.Game/Screens/Play/InGameScoreContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index 0ebf475e18..edccf6c45b 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -90,9 +90,11 @@ namespace osu.Game.Screens.Play var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); var orderedPositions = this.OrderByDescending(i => i.ScorePosition.HasValue).ThenBy(i => i.ScorePosition).Select(i => i.ScorePosition).ToList(); + var newDeclaredPosition = maxPosition + 1; + for (int i = 0; i < Count; i++) { - int newPosition = orderedPositions[i] ?? maxPosition + 1; + int newPosition = orderedPositions[i] ?? newDeclaredPosition; SetLayoutPosition(orderedByScore[i], newPosition); orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; From 5e4e15033025258a2ec6212c782c8cd72380d5f9 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:20:45 +0300 Subject: [PATCH 07/20] Use normal Action --- osu.Game/Screens/Play/InGameScoreContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index edccf6c45b..2d45158095 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Play /// Called once an item's score has changed. /// Useful for doing calculations on what score to show or hide next. (scrolling system) /// - public event Action OnScoreChange; + public Action OnScoreChange; /// /// Whether to declare a new position for un-positioned players. From 9325c024bb08dcd468cc41a0f70d3df7f09f5d78 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:26:01 +0300 Subject: [PATCH 08/20] Add InitialPosition field --- osu.Game/Screens/Play/InGameScoreContainer.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index 2d45158095..36dbec7fce 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -61,19 +61,18 @@ namespace osu.Game.Screens.Play /// Adds a score item based off a with an initial position. /// /// The score info to use for this item. - /// The initial position of this item. + /// The initial position of this item. /// Returns the drawable score item of that player. - public InGameScoreItem AddScore(ScoreInfo score, int? position = null) => score != null ? addScore(score.TotalScore, score.User, position) : null; + public InGameScoreItem AddScore(ScoreInfo score, int? initialPosition = null) => score != null ? addScore(score.TotalScore, score.User, initialPosition) : null; private int maxPosition => this.Where(i => i.ScorePosition.HasValue).Max(i => i.ScorePosition) ?? 0; private InGameScoreItem addScore(double totalScore, User user = null, int? position = null) { - var scoreItem = new InGameScoreItem + var scoreItem = new InGameScoreItem(position) { User = user, TotalScore = totalScore, - ScorePosition = position, OnScoreChange = updateScores, }; @@ -117,6 +116,7 @@ namespace osu.Game.Screens.Play public Action OnScoreChange; private int? scorePosition; + public int? InitialPosition; public int? ScorePosition { @@ -159,7 +159,7 @@ namespace osu.Game.Screens.Play } } - public InGameScoreItem() + public InGameScoreItem(int? initialPosition) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -219,6 +219,8 @@ namespace osu.Game.Screens.Play }, }, }; + + InitialPosition = ScorePosition = initialPosition; } [BackgroundDependencyLoader] From 91f35dde58a3815ba25d731c6ed5fad8da1e98ab Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:27:49 +0300 Subject: [PATCH 09/20] Actual fix of position declaring bug --- osu.Game/Screens/Play/InGameScoreContainer.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index 36dbec7fce..3949307dca 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -65,7 +65,7 @@ namespace osu.Game.Screens.Play /// Returns the drawable score item of that player. public InGameScoreItem AddScore(ScoreInfo score, int? initialPosition = null) => score != null ? addScore(score.TotalScore, score.User, initialPosition) : null; - private int maxPosition => this.Where(i => i.ScorePosition.HasValue).Max(i => i.ScorePosition) ?? 0; + private int maxPosition => this.Max(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition) ?? 0; private InGameScoreItem addScore(double totalScore, User user = null, int? position = null) { @@ -87,13 +87,11 @@ namespace osu.Game.Screens.Play private void reorderPositions() { var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); - var orderedPositions = this.OrderByDescending(i => i.ScorePosition.HasValue).ThenBy(i => i.ScorePosition).Select(i => i.ScorePosition).ToList(); - - var newDeclaredPosition = maxPosition + 1; + var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); for (int i = 0; i < Count; i++) { - int newPosition = orderedPositions[i] ?? newDeclaredPosition; + int newPosition = orderedPositions[i] ?? maxPosition + 1; SetLayoutPosition(orderedByScore[i], newPosition); orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; From f5daf98aa530173f9e83dfc5a1b90b1fb2fd1591 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:28:40 +0300 Subject: [PATCH 10/20] Reset player state on setup --- .../Visual/Gameplay/TestSceneInGameLeaderboard.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 4a861428de..096b29d496 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -41,7 +41,12 @@ namespace osu.Game.Tests.Visual.Gameplay } [SetUp] - public void SetUp() => leaderboard.ClearScores(); + public void SetUp() + { + leaderboard.ClearScores(); + leaderboard.PlayerPosition = 1; + playerScore.Value = 1222333; + } [Test] public void TestPlayerScore() From 598c02f8b9f266c1dbd3d0d2ee196a2ee7a28d73 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:31:32 +0300 Subject: [PATCH 11/20] Shorten Where().FirstOrDefault() --- osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 096b29d496..24b8033fbc 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -78,7 +78,7 @@ namespace osu.Game.Tests.Visual.Gameplay public bool CheckPositionByUsername(string username, int? estimatedPosition) { - var scoreItem = ScoresContainer.Where(i => i.User.Username == username).FirstOrDefault(); + var scoreItem = ScoresContainer.FirstOrDefault(i => i.User.Username == username); return scoreItem != null && scoreItem.ScorePosition == estimatedPosition; } From fdd00c0820355b10b8450e449512cd8067fb77ff Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:35:53 +0300 Subject: [PATCH 12/20] Remove position fading Unnecessary effect --- osu.Game/Screens/Play/InGameScoreContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index 3949307dca..f548b3de3f 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -126,8 +126,8 @@ namespace osu.Game.Screens.Play if (scorePosition.HasValue) positionText.Text = $"#{scorePosition.Value.ToMetric(decimals: scorePosition < 100000 ? 1 : 0)}"; - positionText.FadeTo(scorePosition.HasValue ? 1 : 0, 100); - positionSymbol.FadeTo(scorePosition.HasValue ? 1 : 0, 100); + positionText.FadeTo(scorePosition.HasValue ? 1 : 0); + positionSymbol.FadeTo(scorePosition.HasValue ? 1 : 0); } } From ca7a812e1cc822152ceff303d1323a608b6e141a Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 18:39:42 +0300 Subject: [PATCH 13/20] Add PlayerPosition property --- osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 24b8033fbc..cd211d06ec 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -75,6 +75,11 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestInGameLeaderboard : InGameLeaderboard { public void ClearScores() => ScoresContainer.RemoveAll(s => s.User.Username != PlayerUser.Username); + public int? PlayerPosition + { + get => PlayerScoreItem.ScorePosition; + set => PlayerScoreItem.ScorePosition = value; + } public bool CheckPositionByUsername(string username, int? estimatedPosition) { From 472af16015c40745f59fa759e362f637f57e0f44 Mon Sep 17 00:00:00 2001 From: iiSaLMaN Date: Sun, 4 Aug 2019 19:17:45 +0300 Subject: [PATCH 14/20] Revert unintended change --- .../Visual/Gameplay/TestSceneInGameLeaderboard.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index cd211d06ec..0019212dfa 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -44,7 +44,6 @@ namespace osu.Game.Tests.Visual.Gameplay public void SetUp() { leaderboard.ClearScores(); - leaderboard.PlayerPosition = 1; playerScore.Value = 1222333; } @@ -75,11 +74,6 @@ namespace osu.Game.Tests.Visual.Gameplay private class TestInGameLeaderboard : InGameLeaderboard { public void ClearScores() => ScoresContainer.RemoveAll(s => s.User.Username != PlayerUser.Username); - public int? PlayerPosition - { - get => PlayerScoreItem.ScorePosition; - set => PlayerScoreItem.ScorePosition = value; - } public bool CheckPositionByUsername(string username, int? estimatedPosition) { From 8362ad37e34c10d2ada7bd4468d851d6debdb45a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 15:22:14 +0900 Subject: [PATCH 15/20] Bring up-to-date with code changes --- .../Gameplay/TestSceneInGameLeaderboard.cs | 26 ++++++++----------- osu.Game/Screens/Play/InGameScoreContainer.cs | 3 ++- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 0019212dfa..4944a6477d 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -1,12 +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; -using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; +using osu.Framework.Testing; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK; @@ -16,12 +15,6 @@ namespace osu.Game.Tests.Visual.Gameplay [TestFixture] public class TestSceneInGameLeaderboard : OsuTestScene { - public override IReadOnlyList RequiredTypes => new[] - { - typeof(InGameLeaderboard), - typeof(InGameScoreContainer), - }; - private readonly TestInGameLeaderboard leaderboard; private readonly BindableDouble playerScore; @@ -35,18 +28,21 @@ namespace osu.Game.Tests.Visual.Gameplay RelativeSizeAxes = Axes.X, PlayerCurrentScore = { BindTarget = playerScore = new BindableDouble(1222333) } }); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("reset leaderboard", () => + { + leaderboard.ClearScores(); + playerScore.Value = 1222333; + }); AddStep("add player user", () => leaderboard.PlayerUser = new User { Username = "You" }); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } - [SetUp] - public void SetUp() - { - leaderboard.ClearScores(); - playerScore.Value = 1222333; - } - [Test] public void TestPlayerScore() { diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index f548b3de3f..d3ec132351 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -6,6 +6,7 @@ using System.Linq; using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; @@ -210,7 +211,7 @@ namespace osu.Game.Screens.Play }, scoreText = new GlowingSpriteText { - GlowColour = OsuColour.FromHex(@"83ccfa"), + GlowColour = Color4Extensions.FromHex(@"83ccfa"), Font = OsuFont.Numeric.With(size: 14), } } From dd5572b20a9336562e30bcf14d4bc444d8d0f3be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 15:26:20 +0900 Subject: [PATCH 16/20] Remove unnecessary methods and event --- osu.Game/Screens/Play/InGameScoreContainer.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/InGameScoreContainer.cs index d3ec132351..693020fc4c 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/InGameScoreContainer.cs @@ -19,12 +19,6 @@ namespace osu.Game.Screens.Play { public class InGameScoreContainer : FillFlowContainer { - /// - /// Called once an item's score has changed. - /// Useful for doing calculations on what score to show or hide next. (scrolling system) - /// - public Action OnScoreChange; - /// /// Whether to declare a new position for un-positioned players. /// Must be disabled for online leaderboards with top 50 scores only. @@ -101,9 +95,16 @@ namespace osu.Game.Screens.Play private void updateScores() { - reorderPositions(); + var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); + var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); - OnScoreChange?.Invoke(); + for (int i = 0; i < Count; i++) + { + int newPosition = orderedPositions[i] ?? maxPosition + 1; + + SetLayoutPosition(orderedByScore[i], newPosition); + orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; + } } } From 8b68ccc0ff96f2bd0ae9b3076cdc19e2bff3ac26 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 15:27:26 +0900 Subject: [PATCH 17/20] Rename class and move inside HUD namespace --- .../Gameplay/TestSceneInGameLeaderboard.cs | 34 +++--- .../Screens/Play/HUD/GameplayLeaderboard.cs | 104 ++++++++++++++++++ .../GameplayLeaderboardScore.cs} | 100 +---------------- osu.Game/Screens/Play/InGameLeaderboard.cs | 42 ------- 4 files changed, 122 insertions(+), 158 deletions(-) create mode 100644 osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs rename osu.Game/Screens/Play/{InGameScoreContainer.cs => HUD/GameplayLeaderboardScore.cs} (52%) delete mode 100644 osu.Game/Screens/Play/InGameLeaderboard.cs diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs index 4944a6477d..657eb7e8ba 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs @@ -6,27 +6,27 @@ using NUnit.Framework; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Testing; -using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; using osu.Game.Users; using osuTK; namespace osu.Game.Tests.Visual.Gameplay { [TestFixture] - public class TestSceneInGameLeaderboard : OsuTestScene + public class TestSceneGameplayLeaderboard : OsuTestScene { - private readonly TestInGameLeaderboard leaderboard; - private readonly BindableDouble playerScore; + private readonly TestGameplayLeaderboard leaderboard; - public TestSceneInGameLeaderboard() + private readonly BindableDouble playerScore = new BindableDouble(); + + public TestSceneGameplayLeaderboard() { - Add(leaderboard = new TestInGameLeaderboard + Add(leaderboard = new TestGameplayLeaderboard { Anchor = Anchor.Centre, Origin = Anchor.Centre, Scale = new Vector2(2), RelativeSizeAxes = Axes.X, - PlayerCurrentScore = { BindTarget = playerScore = new BindableDouble(1222333) } }); } @@ -35,11 +35,11 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("reset leaderboard", () => { - leaderboard.ClearScores(); + leaderboard.Clear(); playerScore.Value = 1222333; }); - AddStep("add player user", () => leaderboard.PlayerUser = new User { Username = "You" }); + AddStep("add player user", () => leaderboard.AddRealTimePlayer(playerScore, new User { Username = "You" })); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => leaderboard.AddDummyPlayer(player2Score, "Player 2")); - AddStep("add player 3", () => leaderboard.AddDummyPlayer(player3Score, "Player 3")); + AddStep("add player 2", () => leaderboard.AddRealTimePlayer(player2Score, new User { Username = "Player 2" })); + AddStep("add player 3", () => leaderboard.AddRealTimePlayer(player3Score, new User { Username = "Player 3" })); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); @@ -67,18 +67,14 @@ namespace osu.Game.Tests.Visual.Gameplay AddAssert("is player 2 position #3", () => leaderboard.CheckPositionByUsername("Player 2", 3)); } - private class TestInGameLeaderboard : InGameLeaderboard + private class TestGameplayLeaderboard : GameplayLeaderboard { - public void ClearScores() => ScoresContainer.RemoveAll(s => s.User.Username != PlayerUser.Username); - - public bool CheckPositionByUsername(string username, int? estimatedPosition) + public bool CheckPositionByUsername(string username, int? expectedPosition) { - var scoreItem = ScoresContainer.FirstOrDefault(i => i.User.Username == username); + var scoreItem = this.FirstOrDefault(i => i.User.Username == username); - return scoreItem != null && scoreItem.ScorePosition == estimatedPosition; + return scoreItem != null && scoreItem.ScorePosition == expectedPosition; } - - public void AddDummyPlayer(BindableDouble currentScore, string username) => ScoresContainer.AddRealTimePlayer(currentScore, new User { Username = username }); } } } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs new file mode 100644 index 0000000000..9e1b9a3958 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -0,0 +1,104 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Scoring; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Screens.Play.HUD +{ + public class GameplayLeaderboard : FillFlowContainer + { + /// + /// Whether to declare a new position for un-positioned players. + /// Must be disabled for online leaderboards with top 50 scores only. + /// + public bool DeclareNewPosition = true; + + public GameplayLeaderboard() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(2.5f); + LayoutDuration = 500; + LayoutEasing = Easing.OutQuint; + } + + /// + /// Adds a real-time player score item whose score is updated via a . + /// + /// The bindable current score of the player. + /// The player user. + /// Returns the drawable score item of that player. + public GameplayLeaderboardScore AddRealTimePlayer(BindableDouble currentScore, User user = null) + { + if (currentScore == null) + return null; + + var scoreItem = addScore(currentScore.Value, user); + currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; + + return scoreItem; + } + + /// + /// Adds a score item based off a with an initial position. + /// + /// The score info to use for this item. + /// The initial position of this item. + /// Returns the drawable score item of that player. + public GameplayLeaderboardScore AddScore(ScoreInfo score, int? initialPosition = null) => score != null ? addScore(score.TotalScore, score.User, initialPosition) : null; + + private int maxPosition => this.Max(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition) ?? 0; + + private GameplayLeaderboardScore addScore(double totalScore, User user = null, int? position = null) + { + var scoreItem = new GameplayLeaderboardScore(position) + { + User = user, + TotalScore = totalScore, + OnScoreChange = updateScores, + }; + + Add(scoreItem); + SetLayoutPosition(scoreItem, position ?? maxPosition + 1); + + reorderPositions(); + + return scoreItem; + } + + private void reorderPositions() + { + var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); + var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); + + for (int i = 0; i < Count; i++) + { + int newPosition = orderedPositions[i] ?? maxPosition + 1; + + SetLayoutPosition(orderedByScore[i], newPosition); + orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; + } + } + + private void updateScores() + { + var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); + var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); + + for (int i = 0; i < Count; i++) + { + int newPosition = orderedPositions[i] ?? maxPosition + 1; + + SetLayoutPosition(orderedByScore[i], newPosition); + orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; + } + } + } +} diff --git a/osu.Game/Screens/Play/InGameScoreContainer.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs similarity index 52% rename from osu.Game/Screens/Play/InGameScoreContainer.cs rename to osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 693020fc4c..3af7345ae1 100644 --- a/osu.Game/Screens/Play/InGameScoreContainer.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -2,113 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using Humanizer; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Scoring; using osu.Game.Users; using osuTK; -namespace osu.Game.Screens.Play +namespace osu.Game.Screens.Play.HUD { - public class InGameScoreContainer : FillFlowContainer - { - /// - /// Whether to declare a new position for un-positioned players. - /// Must be disabled for online leaderboards with top 50 scores only. - /// - public bool DeclareNewPosition = true; - - public InGameScoreContainer() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Direction = FillDirection.Vertical; - Spacing = new Vector2(2.5f); - LayoutDuration = 500; - LayoutEasing = Easing.OutQuint; - } - - /// - /// Adds a real-time player score item whose score is updated via a . - /// - /// The bindable current score of the player. - /// The player user. - /// Returns the drawable score item of that player. - public InGameScoreItem AddRealTimePlayer(BindableDouble currentScore, User user = null) - { - if (currentScore == null) - return null; - - var scoreItem = addScore(currentScore.Value, user); - currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; - - return scoreItem; - } - - /// - /// Adds a score item based off a with an initial position. - /// - /// The score info to use for this item. - /// The initial position of this item. - /// Returns the drawable score item of that player. - public InGameScoreItem AddScore(ScoreInfo score, int? initialPosition = null) => score != null ? addScore(score.TotalScore, score.User, initialPosition) : null; - - private int maxPosition => this.Max(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition) ?? 0; - - private InGameScoreItem addScore(double totalScore, User user = null, int? position = null) - { - var scoreItem = new InGameScoreItem(position) - { - User = user, - TotalScore = totalScore, - OnScoreChange = updateScores, - }; - - Add(scoreItem); - SetLayoutPosition(scoreItem, position ?? maxPosition + 1); - - reorderPositions(); - - return scoreItem; - } - - private void reorderPositions() - { - var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); - var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); - - for (int i = 0; i < Count; i++) - { - int newPosition = orderedPositions[i] ?? maxPosition + 1; - - SetLayoutPosition(orderedByScore[i], newPosition); - orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; - } - } - - private void updateScores() - { - var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); - var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); - - for (int i = 0; i < Count; i++) - { - int newPosition = orderedPositions[i] ?? maxPosition + 1; - - SetLayoutPosition(orderedByScore[i], newPosition); - orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; - } - } - } - - public class InGameScoreItem : CompositeDrawable + public class GameplayLeaderboardScore : CompositeDrawable { private readonly OsuSpriteText positionText, positionSymbol, userString; private readonly GlowingSpriteText scoreText; @@ -159,7 +65,7 @@ namespace osu.Game.Screens.Play } } - public InGameScoreItem(int? initialPosition) + public GameplayLeaderboardScore(int? initialPosition) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; diff --git a/osu.Game/Screens/Play/InGameLeaderboard.cs b/osu.Game/Screens/Play/InGameLeaderboard.cs deleted file mode 100644 index c8f5cf5fd7..0000000000 --- a/osu.Game/Screens/Play/InGameLeaderboard.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Bindables; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Game.Users; - -namespace osu.Game.Screens.Play -{ - public class InGameLeaderboard : CompositeDrawable - { - protected readonly InGameScoreContainer ScoresContainer; - - public readonly BindableDouble PlayerCurrentScore = new BindableDouble(); - - private bool playerItemCreated; - private User playerUser; - - public User PlayerUser - { - get => playerUser; - set - { - playerUser = value; - - if (playerItemCreated) - return; - - ScoresContainer.AddRealTimePlayer(PlayerCurrentScore, playerUser); - playerItemCreated = true; - } - } - - public InGameLeaderboard() - { - AutoSizeAxes = Axes.Y; - - InternalChild = ScoresContainer = new InGameScoreContainer(); - } - } -} From b5ab400ad78ac968b4b5a629bb5aacab39dd63eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 15:44:43 +0900 Subject: [PATCH 18/20] Fix test filename not matching updated class name --- ...InGameLeaderboard.cs => TestSceneGameplayLeaderboard.cs} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename osu.Game.Tests/Visual/Gameplay/{TestSceneInGameLeaderboard.cs => TestSceneGameplayLeaderboard.cs} (89%) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs similarity index 89% rename from osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs rename to osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs index 657eb7e8ba..df970c1c46 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneInGameLeaderboard.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneGameplayLeaderboard.cs @@ -39,7 +39,7 @@ namespace osu.Game.Tests.Visual.Gameplay playerScore.Value = 1222333; }); - AddStep("add player user", () => leaderboard.AddRealTimePlayer(playerScore, new User { Username = "You" })); + AddStep("add player user", () => leaderboard.AddPlayer(playerScore, new User { Username = "You" })); AddSliderStep("set player score", 50, 5000000, 1222333, v => playerScore.Value = v); } @@ -49,8 +49,8 @@ namespace osu.Game.Tests.Visual.Gameplay var player2Score = new BindableDouble(1234567); var player3Score = new BindableDouble(1111111); - AddStep("add player 2", () => leaderboard.AddRealTimePlayer(player2Score, new User { Username = "Player 2" })); - AddStep("add player 3", () => leaderboard.AddRealTimePlayer(player3Score, new User { Username = "Player 3" })); + AddStep("add player 2", () => leaderboard.AddPlayer(player2Score, new User { Username = "Player 2" })); + AddStep("add player 3", () => leaderboard.AddPlayer(player3Score, new User { Username = "Player 3" })); AddAssert("is player 2 position #1", () => leaderboard.CheckPositionByUsername("Player 2", 1)); AddAssert("is player position #2", () => leaderboard.CheckPositionByUsername("You", 2)); From e37089af5e188e7dbb769ba4d891a25b48420412 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 15:44:56 +0900 Subject: [PATCH 19/20] Further code cleanup --- .../Screens/Play/HUD/GameplayLeaderboard.cs | 65 ++++--------------- .../Play/HUD/GameplayLeaderboardScore.cs | 5 +- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 9e1b9a3958..6ee654fb9e 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs @@ -1,11 +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 JetBrains.Annotations; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Game.Scoring; using osu.Game.Users; using osuTK; @@ -13,52 +14,33 @@ namespace osu.Game.Screens.Play.HUD { public class GameplayLeaderboard : FillFlowContainer { - /// - /// Whether to declare a new position for un-positioned players. - /// Must be disabled for online leaderboards with top 50 scores only. - /// - public bool DeclareNewPosition = true; - public GameplayLeaderboard() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + Direction = FillDirection.Vertical; + Spacing = new Vector2(2.5f); - LayoutDuration = 500; + + LayoutDuration = 250; LayoutEasing = Easing.OutQuint; } /// - /// Adds a real-time player score item whose score is updated via a . + /// Adds a player to the leaderboard. /// /// The bindable current score of the player. - /// The player user. - /// Returns the drawable score item of that player. - public GameplayLeaderboardScore AddRealTimePlayer(BindableDouble currentScore, User user = null) + /// The player. + public void AddPlayer([NotNull] BindableDouble currentScore, [NotNull] User user) { - if (currentScore == null) - return null; - var scoreItem = addScore(currentScore.Value, user); currentScore.ValueChanged += s => scoreItem.TotalScore = s.NewValue; - - return scoreItem; } - /// - /// Adds a score item based off a with an initial position. - /// - /// The score info to use for this item. - /// The initial position of this item. - /// Returns the drawable score item of that player. - public GameplayLeaderboardScore AddScore(ScoreInfo score, int? initialPosition = null) => score != null ? addScore(score.TotalScore, score.User, initialPosition) : null; - - private int maxPosition => this.Max(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition) ?? 0; - - private GameplayLeaderboardScore addScore(double totalScore, User user = null, int? position = null) + private GameplayLeaderboardScore addScore(double totalScore, User user) { - var scoreItem = new GameplayLeaderboardScore(position) + var scoreItem = new GameplayLeaderboardScore { User = user, TotalScore = totalScore, @@ -66,38 +48,19 @@ namespace osu.Game.Screens.Play.HUD }; Add(scoreItem); - SetLayoutPosition(scoreItem, position ?? maxPosition + 1); - - reorderPositions(); + updateScores(); return scoreItem; } - private void reorderPositions() - { - var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); - var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); - - for (int i = 0; i < Count; i++) - { - int newPosition = orderedPositions[i] ?? maxPosition + 1; - - SetLayoutPosition(orderedByScore[i], newPosition); - orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; - } - } - private void updateScores() { var orderedByScore = this.OrderByDescending(i => i.TotalScore).ToList(); - var orderedPositions = this.Select(i => this.Any(item => item.InitialPosition.HasValue) ? i.InitialPosition : i.ScorePosition).OrderByDescending(p => p.HasValue).ThenBy(p => p).ToList(); for (int i = 0; i < Count; i++) { - int newPosition = orderedPositions[i] ?? maxPosition + 1; - - SetLayoutPosition(orderedByScore[i], newPosition); - orderedByScore[i].ScorePosition = DeclareNewPosition ? newPosition : orderedPositions[i]; + SetLayoutPosition(orderedByScore[i], i); + orderedByScore[i].ScorePosition = i + 1; } } } diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs index 3af7345ae1..4c75f422c9 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboardScore.cs @@ -22,7 +22,6 @@ namespace osu.Game.Screens.Play.HUD public Action OnScoreChange; private int? scorePosition; - public int? InitialPosition; public int? ScorePosition { @@ -65,7 +64,7 @@ namespace osu.Game.Screens.Play.HUD } } - public GameplayLeaderboardScore(int? initialPosition) + public GameplayLeaderboardScore() { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; @@ -125,8 +124,6 @@ namespace osu.Game.Screens.Play.HUD }, }, }; - - InitialPosition = ScorePosition = initialPosition; } [BackgroundDependencyLoader] From ea6c196f81e72ac967da65218c69f8bf37ce2f9a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 15 Dec 2020 16:03:18 +0900 Subject: [PATCH 20/20] Remove unused using statement --- osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs index 6ee654fb9e..e53c56b390 100644 --- a/osu.Game/Screens/Play/HUD/GameplayLeaderboard.cs +++ b/osu.Game/Screens/Play/HUD/GameplayLeaderboard.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.Linq; using JetBrains.Annotations; using osu.Framework.Bindables;