Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions osu.Game.Tests/Visual/Online/TestSceneRankingsTables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ protected override void LoadComplete()
AddStep("User performance", createPerformanceTable);
AddStep("User scores", createScoreTable);
AddStep("Country scores", createCountryTable);
AddStep("Ranked play ladder", createRankedTable);
}

private void createCountryTable()
Expand Down Expand Up @@ -153,6 +154,26 @@ private void createScoreTable()
loadTable(new ScoresTable(1, createUserStatistics()));
}

private void createRankedTable()
{
onLoadStarted();
loadTable(new MatchmakingTable(1, new List<APIUserMatchmakingStatistics>
{
new APIUserMatchmakingStatistics
{
User = new APIUser
{
Username = "first active user",
CountryCode = CountryCode.JP,
Active = true,
},
FirstPlacements = 10,
Plays = 20,
Rating = 1500,
},
}));
}

private void onLoadStarted()
{
loading.Show();
Expand Down
21 changes: 21 additions & 0 deletions osu.Game/Online/API/Requests/GetMatchmakingPoolsRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// 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.Collections.Generic;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;

namespace osu.Game.Online.API.Requests
{
public class GetMatchmakingPoolsRequest : APIRequest<List<APIMatchmakingPool>>
{
public readonly RulesetInfo Ruleset;

public GetMatchmakingPoolsRequest(RulesetInfo ruleset)
{
Ruleset = ruleset;
}

protected override string Target => @$"rankings/ranked-play/{Ruleset.ShortName}";
}
}
22 changes: 22 additions & 0 deletions osu.Game/Online/API/Requests/GetMatchmakingRankingRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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 osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;

namespace osu.Game.Online.API.Requests
{
public class GetMatchmakingRankingRequest : APIRequest<GetMatchmakingRankingResponse>
{
public readonly RulesetInfo Ruleset;
public readonly APIMatchmakingPool Pool;

public GetMatchmakingRankingRequest(RulesetInfo ruleset, APIMatchmakingPool pool)
{
Ruleset = ruleset;
Pool = pool;
}

protected override string Target => $"rankings/ranked-play/{Ruleset.ShortName}/{Pool.Id}";
}
}
2 changes: 2 additions & 0 deletions osu.Game/Online/API/Requests/Responses/APIMatchmakingPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,7 @@ public class APIMatchmakingPool

[JsonProperty("variant_id")]
public int VariantId { get; set; }

public override string ToString() => Name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace osu.Game.Online.API.Requests.Responses
{
public class APIUserMatchmakingStatistics
{
[JsonProperty("user")]
public APIUser User = new APIUser();

[JsonProperty("user_id")]
public int UserId;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// 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.Collections.Generic;
using Newtonsoft.Json;

namespace osu.Game.Online.API.Requests.Responses
{
public class GetMatchmakingRankingResponse : ResponseWithCursor
{
[JsonProperty("ranking")]
public List<APIUserMatchmakingStatistics> Users = [];
}
}
133 changes: 133 additions & 0 deletions osu.Game/Overlays/Rankings/MatchmakingLayout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// 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.Linq;
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Overlays.Rankings.Tables;
using osu.Game.Rulesets;

namespace osu.Game.Overlays.Rankings
{
public partial class MatchmakingLayout : CompositeDrawable
{
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();

private readonly Bindable<APIMatchmakingPool> selectedPool = new Bindable<APIMatchmakingPool>();

[Resolved]
private IAPIProvider api { get; set; } = null!;

private CancellationTokenSource? cancellationToken;
private GetMatchmakingPoolsRequest? getPoolsRequest;
private GetMatchmakingRankingRequest? getRankingRequest;

private MatchmakingPoolSelector selector = null!;
private Container content = null!;
private LoadingLayer loading = null!;

[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;

InternalChild = new ReverseChildIDFillFlowContainer<Drawable>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
selector = new MatchmakingPoolSelector
{
Current = selectedPool,
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
content = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Margin = new MarginPadding { Vertical = 10 }
},
loading = new LoadingLayer(true)
}
}
}
};
}

protected override void LoadComplete()
{
base.LoadComplete();

selectedPool.BindValueChanged(_ => onPoolChanged());
Ruleset.BindValueChanged(_ => onRulesetChanged());

getMatchmakingPools();
}

private void getMatchmakingPools()
{
getPoolsRequest?.Cancel();

getPoolsRequest = new GetMatchmakingPoolsRequest(Ruleset.Value);
getPoolsRequest.Success += response => Schedule(() => selector.Pools = response);
api.Queue(getPoolsRequest);
}

private void onRulesetChanged()
{
if (!selector.Pools.Any())
return;

selectedPool.TriggerChange();
}

private void onPoolChanged()
{
loading.Show();

cancellationToken?.Cancel();
getRankingRequest?.Cancel();

getRankingRequest = new GetMatchmakingRankingRequest(Ruleset.Value, selectedPool.Value);
getRankingRequest.Success += onSuccess;

api.Queue(getRankingRequest);
}

private void onSuccess(GetMatchmakingRankingResponse response)
{
LoadComponentAsync(new MatchmakingTable(1, response.Users), loaded =>
{
content.Clear();
content.Add(loaded);

loading.Hide();
}, (cancellationToken = new CancellationTokenSource()).Token);
}

protected override void Dispose(bool isDisposing)
{
getPoolsRequest?.Cancel();
getRankingRequest?.Cancel();
cancellationToken?.Cancel();

base.Dispose(isDisposing);
}
}
}
72 changes: 72 additions & 0 deletions osu.Game/Overlays/Rankings/MatchmakingPoolSelector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// 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.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.Graphics.UserInterface;
using osu.Game.Online.API.Requests.Responses;

namespace osu.Game.Overlays.Rankings
{
public partial class MatchmakingPoolSelector : CompositeDrawable, IHasCurrentValue<APIMatchmakingPool>
{
private readonly BindableWithCurrent<APIMatchmakingPool> current = new BindableWithCurrent<APIMatchmakingPool>();

public Bindable<APIMatchmakingPool> Current
{
get => current.Current;
set => current.Current = value;
}

public IEnumerable<APIMatchmakingPool> Pools
{
get => dropdown.Items;
set => dropdown.Items = value;
}

private readonly Box background;
private readonly RankingSelectorDropdown<APIMatchmakingPool> dropdown;

public MatchmakingPoolSelector()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;

InternalChildren = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Horizontal = WaveOverlayContainer.HORIZONTAL_PADDING },
Child = new Container
{
Margin = new MarginPadding { Vertical = 20 },
RelativeSizeAxes = Axes.X,
Height = 40,
Depth = -float.MaxValue,
Child = dropdown = new RankingSelectorDropdown<APIMatchmakingPool>
{
RelativeSizeAxes = Axes.X,
Current = Current
}
},
},
};
}

[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
background.Colour = colourProvider.Dark3;
}
}
}
50 changes: 50 additions & 0 deletions osu.Game/Overlays/Rankings/RankingSelectorDropdown.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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 osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;

namespace osu.Game.Overlays.Rankings
{
public partial class RankingSelectorDropdown<T> : OsuDropdown<T>
where T : class
{
private OsuDropdownMenu menu = null!;

protected override DropdownMenu CreateMenu() => menu = (OsuDropdownMenu)base.CreateMenu().With(m => m.MaxHeight = 400);

protected override DropdownHeader CreateHeader() => new RankingSelectorDropdownHeader();

[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
menu.BackgroundColour = colourProvider.Background5;
menu.HoverColour = colourProvider.Background4;
menu.SelectionColour = colourProvider.Background3;
}

private partial class RankingSelectorDropdownHeader : OsuDropdownHeader
{
public RankingSelectorDropdownHeader()
{
AutoSizeAxes = Axes.Y;
Text.Font = OsuFont.GetFont(size: 15);
Text.Padding = new MarginPadding { Vertical = 1.5f }; // osu-web line-height difference compensation
Foreground.Padding = new MarginPadding { Horizontal = 10, Vertical = 15 };
Margin = Chevron.Margin = new MarginPadding(0);
}

[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
BackgroundColour = colourProvider.Background6.Opacity(0.5f);
// osu-web adds a 0.6 opacity container on top of the 0.5 base one when hovering, 0.8 on a single container here matches the resulting colour
BackgroundColourHover = colourProvider.Background6.Opacity(0.8f);
}
}
}
}
1 change: 1 addition & 0 deletions osu.Game/Overlays/Rankings/RankingsOverlayHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ bool showRulesetSelector(RankingsScope scope)
case RankingsScope.Score:
case RankingsScope.Country:
case RankingsScope.Playlists:
case RankingsScope.Matchmaking:
return true;

default:
Expand Down
3 changes: 3 additions & 0 deletions osu.Game/Overlays/Rankings/RankingsScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public enum RankingsScope
[LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypePlaylists))]
Playlists,

[LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeMatchmaking))]
Matchmaking,

[LocalisableDescription(typeof(RankingsStrings), nameof(RankingsStrings.TypeKudosu))]
Kudosu,
}
Expand Down
Loading
Loading