1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 04:07:25 +08:00

Replace old bad daily challenge leaderboard with new implementation

- Actually shows scores rather than playlist aggregates (which are
  useful... in playlists, where there is more than one item)
- Actually allows scores to be shown by clicking on them
- Doesn't completely break down visually on smaller window sizes

The general appearance is not as polished as the old one in details but
I wanted something quick that we can get out by next weekend.

Also includes the naive method of refetching scores once a new top 50
score is detected. I can add a stagger if required.
This commit is contained in:
Bartłomiej Dach 2024-06-06 11:06:22 +02:00
parent 8e8909c999
commit 5fa586848d
No known key found for this signature in database
6 changed files with 459 additions and 64 deletions

View File

@ -0,0 +1,142 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.OnlinePlay.DailyChallenge;
using osuTK;
namespace osu.Game.Tests.Visual.DailyChallenge
{
public partial class TestSceneDailyChallengeLeaderboard : OsuTestScene
{
private DummyAPIAccess dummyAPI => (DummyAPIAccess)API;
[Cached]
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Plum);
[Test]
public void TestBasicBehaviour()
{
DailyChallengeLeaderboard leaderboard = null!;
AddStep("set up response without user best", () =>
{
dummyAPI.HandleRequest = req =>
{
if (req is IndexPlaylistScoresRequest indexRequest)
{
indexRequest.TriggerSuccess(createResponse(50, false));
return true;
}
return false;
};
});
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.8f),
});
AddStep("set up response with user best", () =>
{
dummyAPI.HandleRequest = req =>
{
if (req is IndexPlaylistScoresRequest indexRequest)
{
indexRequest.TriggerSuccess(createResponse(50, true));
return true;
}
return false;
};
});
AddStep("force refetch", () => leaderboard.RefetchScores());
}
[Test]
public void TestLoadingBehaviour()
{
IndexPlaylistScoresRequest pendingRequest = null!;
DailyChallengeLeaderboard leaderboard = null!;
AddStep("set up requests handler", () =>
{
dummyAPI.HandleRequest = req =>
{
if (req is IndexPlaylistScoresRequest indexRequest)
{
pendingRequest = indexRequest;
return true;
}
return false;
};
});
AddStep("create leaderboard", () => Child = leaderboard = new DailyChallengeLeaderboard(new Room { RoomID = { Value = 1 } }, new PlaylistItem(Beatmap.Value.BeatmapInfo))
{
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(0.8f),
});
AddStep("complete load", () => pendingRequest.TriggerSuccess(createResponse(3, true)));
AddStep("force refetch", () => leaderboard.RefetchScores());
AddStep("complete load", () => pendingRequest.TriggerSuccess(createResponse(4, true)));
}
private IndexedMultiplayerScores createResponse(int scoreCount, bool returnUserBest)
{
var result = new IndexedMultiplayerScores();
for (int i = 0; i < scoreCount; ++i)
{
result.Scores.Add(new MultiplayerScore
{
ID = i,
Accuracy = 1 - (float)i / (2 * scoreCount),
Position = i + 1,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = (ScoreRank)RNG.Next((int)ScoreRank.D, (int)ScoreRank.XH),
MaxCombo = 1000 - i,
TotalScore = (long)(1_000_000 * (1 - (float)i / (2 * scoreCount))),
User = new APIUser { Username = $"user {i}" },
Statistics = new Dictionary<HitResult, int>()
});
}
if (returnUserBest)
{
result.UserScore = new MultiplayerScore
{
ID = 99999,
Accuracy = 0.91,
Position = 4,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.A,
MaxCombo = 100,
TotalScore = 800000,
User = dummyAPI.LocalUser.Value,
Statistics = new Dictionary<HitResult, int>()
};
}
return result;
}
}
}

View File

@ -50,35 +50,73 @@ namespace osu.Game.Tests.Visual.SongSelect
}); });
} }
[SetUp] [Test]
public void Setup() => Schedule(() => public void TestSheared()
{ {
Children = new Drawable[] AddStep("create content", () =>
{ {
fillFlow = new FillFlowContainer Children = new Drawable[]
{ {
Width = relativeWidth, fillFlow = new FillFlowContainer
Anchor = Anchor.Centre, {
Origin = Anchor.Centre, Width = relativeWidth,
RelativeSizeAxes = Axes.X, Anchor = Anchor.Centre,
AutoSizeAxes = Axes.Y, Origin = Anchor.Centre,
Spacing = new Vector2(0f, 2f), RelativeSizeAxes = Axes.X,
Shear = new Vector2(OsuGame.SHEAR, 0) AutoSizeAxes = Axes.Y,
}, Spacing = new Vector2(0f, 2f),
drawWidthText = new OsuSpriteText(), Shear = new Vector2(OsuGame.SHEAR, 0)
}; },
drawWidthText = new OsuSpriteText(),
};
foreach (var scoreInfo in getTestScores()) foreach (var scoreInfo in getTestScores())
{
fillFlow.Add(new LeaderboardScoreV2(scoreInfo)
{
Rank = scoreInfo.Position,
IsPersonalBest = scoreInfo.User.Id == 2,
Shear = Vector2.Zero,
});
}
foreach (var score in fillFlow.Children)
score.Show();
});
}
[Test]
public void TestNonSheared()
{
AddStep("create content", () =>
{ {
fillFlow.Add(new LeaderboardScoreV2(scoreInfo, scoreInfo.Position, scoreInfo.User.Id == 2) Children = new Drawable[]
{ {
Shear = Vector2.Zero, fillFlow = new FillFlowContainer
}); {
} Width = relativeWidth,
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0f, 2f),
},
drawWidthText = new OsuSpriteText(),
};
foreach (var score in fillFlow.Children) foreach (var scoreInfo in getTestScores())
score.Show(); {
}); fillFlow.Add(new LeaderboardScoreV2(scoreInfo)
{
Rank = scoreInfo.Position,
IsPersonalBest = scoreInfo.User.Id == 2,
});
}
foreach (var score in fillFlow.Children)
score.Show();
});
}
[SetUpSteps] [SetUpSteps]
public void SetUpSteps() public void SetUpSteps()

View File

@ -49,7 +49,7 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
private readonly Bindable<IReadOnlyList<Mod>> userMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>()); private readonly Bindable<IReadOnlyList<Mod>> userMods = new Bindable<IReadOnlyList<Mod>>(Array.Empty<Mod>());
private OnlinePlayScreenWaveContainer waves = null!; private OnlinePlayScreenWaveContainer waves = null!;
private MatchLeaderboard leaderboard = null!; private DailyChallengeLeaderboard leaderboard = null!;
private RoomModSelectOverlay userModsSelectOverlay = null!; private RoomModSelectOverlay userModsSelectOverlay = null!;
private Sample? sampleStart; private Sample? sampleStart;
private IDisposable? userModsSelectOverlayRegistration; private IDisposable? userModsSelectOverlayRegistration;
@ -208,33 +208,17 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
feed = new DailyChallengeEventFeed feed = new DailyChallengeEventFeed
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
PresentScore = id => PresentScore = presentScore
{
if (this.IsCurrentScreen())
this.Push(new PlaylistItemScoreResultsScreen(room.RoomID.Value!.Value, playlistItem, id));
}
} }
], ],
}, },
}, },
null, null,
// Middle column (leaderboard) // Middle column (leaderboard)
new GridContainer leaderboard = new DailyChallengeLeaderboard(room, playlistItem)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Content = new[] PresentScore = presentScore,
{
new Drawable[]
{
new SectionHeader("Leaderboard")
},
[leaderboard = new MatchLeaderboard { RelativeSizeAxes = Axes.Both }],
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
}
}, },
// Spacer // Spacer
null, null,
@ -330,6 +314,12 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet; metadataClient.MultiplayerRoomScoreSet += onRoomScoreSet;
} }
private void presentScore(long id)
{
if (this.IsCurrentScreen())
this.Push(new PlaylistItemScoreResultsScreen(room.RoomID.Value!.Value, playlistItem, id));
}
private void onRoomScoreSet(MultiplayerRoomScoreSetEvent e) private void onRoomScoreSet(MultiplayerRoomScoreSetEvent e)
{ {
if (e.RoomID != room.RoomID.Value || e.PlaylistItemID != playlistItem.ID) if (e.RoomID != room.RoomID.Value || e.PlaylistItemID != playlistItem.ID)
@ -351,6 +341,9 @@ namespace osu.Game.Screens.OnlinePlay.DailyChallenge
{ {
breakdown.AddNewScore(ev); breakdown.AddNewScore(ev);
feed.AddNewScore(ev); feed.AddNewScore(ev);
if (e.NewRank <= 50)
Schedule(() => leaderboard.RefetchScores());
}); });
}); });
} }

View File

@ -0,0 +1,175 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Screens.SelectV2.Leaderboards;
using osuTK;
namespace osu.Game.Screens.OnlinePlay.DailyChallenge
{
public partial class DailyChallengeLeaderboard : CompositeDrawable
{
public Action<long>? PresentScore { get; init; }
private readonly Room room;
private readonly PlaylistItem playlistItem;
private FillFlowContainer<LeaderboardScoreV2> scoreFlow = null!;
private Container userBestContainer = null!;
private SectionHeader userBestHeader = null!;
private LoadingLayer loadingLayer = null!;
private CancellationTokenSource? cancellationTokenSource;
[Resolved]
private IAPIProvider api { get; set; } = null!;
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
[Resolved]
private RulesetStore rulesets { get; set; } = null!;
[Resolved]
private IBindable<WorkingBeatmap> beatmap { get; set; } = null!;
public DailyChallengeLeaderboard(Room room, PlaylistItem playlistItem)
{
this.room = room;
this.playlistItem = playlistItem;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new GridContainer
{
RelativeSizeAxes = Axes.Both,
RowDimensions =
[
new Dimension(GridSizeMode.AutoSize),
new Dimension(),
new Dimension(GridSizeMode.AutoSize),
new Dimension(GridSizeMode.AutoSize)
],
Content = new[]
{
new Drawable[] { new SectionHeader("Leaderboard") },
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new OsuScrollContainer
{
RelativeSizeAxes = Axes.Both,
Child = scoreFlow = new FillFlowContainer<LeaderboardScoreV2>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Right = 20, },
Direction = FillDirection.Vertical,
Spacing = new Vector2(5),
Scale = new Vector2(0.8f),
Width = 1 / 0.8f,
}
},
loadingLayer = new LoadingLayer
{
RelativeSizeAxes = Axes.Both,
},
}
}
},
new Drawable[] { userBestHeader = new SectionHeader("Personal best") { Alpha = 0, } },
new Drawable[]
{
userBestContainer = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Right = 20, },
Scale = new Vector2(0.8f),
Width = 1 / 0.8f,
}
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
RefetchScores();
}
public void RefetchScores()
{
var request = new IndexPlaylistScoresRequest(room.RoomID.Value!.Value, playlistItem.ID);
request.Success += req =>
{
var best = req.Scores.Select(s => s.CreateScoreInfo(scoreManager, rulesets, playlistItem, beatmap.Value.BeatmapInfo)).ToArray();
var userBest = req.UserScore?.CreateScoreInfo(scoreManager, rulesets, playlistItem, beatmap.Value.BeatmapInfo);
cancellationTokenSource?.Cancel();
cancellationTokenSource = null;
cancellationTokenSource ??= new CancellationTokenSource();
if (best.Length == 0)
{
scoreFlow.Clear();
loadingLayer.Hide();
}
else
{
LoadComponentsAsync(best.Select(s => new LeaderboardScoreV2(s, sheared: false)
{
Rank = s.Position,
IsPersonalBest = s.UserID == api.LocalUser.Value.Id,
Action = () => PresentScore?.Invoke(s.OnlineID),
}), loaded =>
{
scoreFlow.Clear();
scoreFlow.AddRange(loaded);
scoreFlow.FadeTo(1, 400, Easing.OutQuint);
loadingLayer.Hide();
}, cancellationTokenSource.Token);
}
userBestContainer.Clear();
if (userBest != null)
{
userBestContainer.Add(new LeaderboardScoreV2(userBest, sheared: false)
{
Rank = userBest.Position,
IsPersonalBest = true,
Action = () => PresentScore?.Invoke(userBest.OnlineID),
});
}
userBestHeader.FadeTo(userBest == null ? 0 : 1);
};
loadingLayer.Show();
scoreFlow.FadeTo(0.5f, 400, Easing.OutQuint);
api.Queue(request);
}
}
}

View File

@ -43,6 +43,9 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
public partial class LeaderboardScoreV2 : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip<ScoreInfo> public partial class LeaderboardScoreV2 : OsuClickableContainer, IHasContextMenu, IHasCustomTooltip<ScoreInfo>
{ {
public int? Rank { get; init; }
public bool IsPersonalBest { get; init; }
private const float expanded_right_content_width = 210; private const float expanded_right_content_width = 210;
private const float grade_width = 40; private const float grade_width = 40;
private const float username_min_width = 125; private const float username_min_width = 125;
@ -52,15 +55,12 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
private const float rank_label_visibility_width_cutoff = rank_label_width + height + username_min_width + statistics_regular_min_width + expanded_right_content_width; private const float rank_label_visibility_width_cutoff = rank_label_width + height + username_min_width + statistics_regular_min_width + expanded_right_content_width;
private readonly ScoreInfo score; private readonly ScoreInfo score;
private readonly bool sheared;
private const int height = 60; private const int height = 60;
private const int corner_radius = 10; private const int corner_radius = 10;
private const int transition_duration = 200; private const int transition_duration = 200;
private readonly int? rank;
private readonly bool isPersonalBest;
private Colour4 foregroundColour; private Colour4 foregroundColour;
private Colour4 backgroundColour; private Colour4 backgroundColour;
private ColourInfo totalScoreBackgroundGradient; private ColourInfo totalScoreBackgroundGradient;
@ -104,13 +104,12 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
public ITooltip<ScoreInfo> GetCustomTooltip() => new LeaderboardScoreTooltip(); public ITooltip<ScoreInfo> GetCustomTooltip() => new LeaderboardScoreTooltip();
public virtual ScoreInfo TooltipContent => score; public virtual ScoreInfo TooltipContent => score;
public LeaderboardScoreV2(ScoreInfo score, int? rank, bool isPersonalBest = false) public LeaderboardScoreV2(ScoreInfo score, bool sheared = true)
{ {
this.score = score; this.score = score;
this.rank = rank; this.sheared = sheared;
this.isPersonalBest = isPersonalBest;
Shear = new Vector2(OsuGame.SHEAR, 0); Shear = new Vector2(sheared ? OsuGame.SHEAR : 0, 0);
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Height = height; Height = height;
} }
@ -120,8 +119,8 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
var user = score.User; var user = score.User;
foregroundColour = isPersonalBest ? colourProvider.Background1 : colourProvider.Background5; foregroundColour = IsPersonalBest ? colourProvider.Background1 : colourProvider.Background5;
backgroundColour = isPersonalBest ? colourProvider.Background2 : colourProvider.Background4; backgroundColour = IsPersonalBest ? colourProvider.Background2 : colourProvider.Background4;
totalScoreBackgroundGradient = ColourInfo.GradientHorizontal(backgroundColour.Opacity(0), backgroundColour); totalScoreBackgroundGradient = ColourInfo.GradientHorizontal(backgroundColour.Opacity(0), backgroundColour);
statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s, score) statisticsLabels = GetStatistics(score).Select(s => new ScoreComponentLabel(s, score)
@ -159,7 +158,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
Child = rankLabel = new RankLabel(rank) Child = rankLabel = new RankLabel(Rank, sheared)
{ {
Width = rank_label_width, Width = rank_label_width,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
@ -243,7 +242,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
User = score.User, User = score.User,
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft, Origin = Anchor.BottomLeft,
Colour = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0.5f), Colour4.FromHex(@"222A27").Opacity(1)), Colour = ColourInfo.GradientHorizontal(Colour4.White.Opacity(0.5f), Colour4.FromHex(@"222A27").Opacity(1)),
@ -274,7 +273,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Scale = new Vector2(1.1f), Scale = new Vector2(1.1f),
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}) })
{ {
@ -292,7 +291,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Colour4.Black.Opacity(0.5f), Colour = Colour4.Black.Opacity(0.5f),
}, },
new RankLabel(rank) new RankLabel(Rank, sheared)
{ {
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
@ -314,7 +313,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
flagBadgeAndDateContainer = new FillFlowContainer flagBadgeAndDateContainer = new FillFlowContainer
{ {
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Spacing = new Vector2(5), Spacing = new Vector2(5),
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -338,7 +337,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
nameLabel = new TruncatingSpriteText nameLabel = new TruncatingSpriteText
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Text = user.Username, Text = user.Username,
Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold) Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold)
} }
@ -354,7 +353,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
Name = @"Statistics container", Name = @"Statistics container",
Padding = new MarginPadding { Right = 40 }, Padding = new MarginPadding { Right = 40 },
Spacing = new Vector2(25, 0), Spacing = new Vector2(25, 0),
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
@ -412,7 +411,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
}, },
RankContainer = new Container RankContainer = new Container
{ {
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
@ -470,7 +469,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
UseFullGlyphHeight = false, UseFullGlyphHeight = false,
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Current = scoreManager.GetBindableTotalScoreString(score), Current = scoreManager.GetBindableTotalScoreString(score),
Font = OsuFont.GetFont(size: 30, weight: FontWeight.Light), Font = OsuFont.GetFont(size: 30, weight: FontWeight.Light),
}, },
@ -478,7 +477,7 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Spacing = new Vector2(2f, 0f), Spacing = new Vector2(2f, 0f),
@ -656,14 +655,14 @@ namespace osu.Game.Screens.SelectV2.Leaderboards
private partial class RankLabel : Container, IHasTooltip private partial class RankLabel : Container, IHasTooltip
{ {
public RankLabel(int? rank) public RankLabel(int? rank, bool sheared)
{ {
if (rank >= 1000) if (rank >= 1000)
TooltipText = $"#{rank:N0}"; TooltipText = $"#{rank:N0}";
Child = new OsuSpriteText Child = new OsuSpriteText
{ {
Shear = new Vector2(-OsuGame.SHEAR, 0), Shear = new Vector2(sheared ? -OsuGame.SHEAR : 0, 0),
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold, italics: true), Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold, italics: true),

View File

@ -99,6 +99,54 @@ namespace osu.Game.Tests.Visual.OnlinePlay
}); });
return true; return true;
case IndexPlaylistScoresRequest roomLeaderboardRequest:
roomLeaderboardRequest.TriggerSuccess(new IndexedMultiplayerScores
{
Scores =
{
new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 1,
Position = 1,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.S,
MaxCombo = 1000,
TotalScore = 1000000,
User = new APIUser { Username = "best user" },
Statistics = new Dictionary<HitResult, int>()
},
new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 0.7,
Position = 2,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.B,
MaxCombo = 100,
TotalScore = 200000,
User = new APIUser { Username = "worst user" },
Statistics = new Dictionary<HitResult, int>()
},
},
UserScore = new MultiplayerScore
{
ID = currentScoreId++,
Accuracy = 0.91,
Position = 4,
EndedAt = DateTimeOffset.Now,
Passed = true,
Rank = ScoreRank.A,
MaxCombo = 100,
TotalScore = 800000,
User = localUser,
Statistics = new Dictionary<HitResult, int>()
},
});
return true;
case PartRoomRequest partRoomRequest: case PartRoomRequest partRoomRequest:
partRoomRequest.TriggerSuccess(); partRoomRequest.TriggerSuccess();
return true; return true;