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
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private partial class TestLeaderboard : MultiplayerLeaderboardProvider
public Dictionary<int, IReadOnlyList<Mod>> UserMods => UserScores.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.ScoreProcessor.Mods);

public TestLeaderboard(MultiplayerRoomUser[] users)
: base(users)
: base(users, false)
{
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected override MultiplayerRoomUser CreateUser(int userId)
}

protected override MultiplayerLeaderboardProvider CreateLeaderboardProvider() =>
new MultiplayerLeaderboardProvider(MultiplayerUsers.ToArray())
new MultiplayerLeaderboardProvider(MultiplayerUsers.ToArray(), false)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Expand Down
16 changes: 16 additions & 0 deletions osu.Game.Tests/Visual/RankedPlay/TestSceneRankedPlayUserDisplay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.Rooms;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay;
using osu.Game.Screens.OnlinePlay.Matchmaking.RankedPlay.Components;
using osu.Game.Tests.Visual.Multiplayer;
Expand Down Expand Up @@ -90,5 +92,19 @@ public void TestLastStand()
health.Value = 1;
});
}

[Test]
public void TestMods()
{
AddStep("set user mods", () => MultiplayerClient.ChangeUserMods(1001, [new APIMod(new OsuModHidden())]));

AddStep("reverse orientation", () => Child = new RankedPlayUserDisplay(new APIUser { Id = 1001, Username = "User 1001" }, Anchor.BottomRight, RankedPlayColourScheme.BLUE)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(256, 72),
Health = { BindTarget = health }
});
}
}
}
2 changes: 1 addition & 1 deletion osu.Game/Online/Matchmaking/IMatchmakingServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public interface IMatchmakingServer
/// <summary>
/// Joins the matchmaking queue, allowing the local user to get matched up with others.
/// </summary>
Task MatchmakingJoinQueue(int poolId);
Task<MatchmakingJoinQueueResponse> MatchmakingJoinQueueWithParams(MatchmakingJoinQueueRequest request);

/// <summary>
/// Leaves the matchmaking queue.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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 MessagePack;
using osu.Game.Online.API;

namespace osu.Game.Online.Matchmaking.Requests
{
[MessagePackObject]
[Serializable]
public class MatchmakingJoinQueueRequest
{
[Key(0)]
public int PoolId { get; set; }

[Key(1)]
public APIMod[] Mods { get; set; } = [];
}
}
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;
using MessagePack;

namespace osu.Game.Online.Matchmaking.Responses
{
[MessagePackObject]
[Serializable]
public class MatchmakingJoinQueueResponse
{
}
}
2 changes: 1 addition & 1 deletion osu.Game/Online/Multiplayer/MultiplayerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1210,7 +1210,7 @@ public RankedPlayCardWithPlaylistItem GetCardWithPlaylistItem(RankedPlayCardItem

public abstract Task MatchmakingLeaveLobby();

public abstract Task MatchmakingJoinQueue(int poolId);
public abstract Task<MatchmakingJoinQueueResponse> MatchmakingJoinQueueWithParams(MatchmakingJoinQueueRequest request);

public abstract Task MatchmakingLeaveQueue();

Expand Down
6 changes: 3 additions & 3 deletions osu.Game/Online/Multiplayer/OnlineMultiplayerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -383,13 +383,13 @@ public override Task MatchmakingLeaveLobby()
return connection.InvokeAsync(nameof(IMatchmakingServer.MatchmakingLeaveLobby));
}

public override Task MatchmakingJoinQueue(int poolId)
public override Task<MatchmakingJoinQueueResponse> MatchmakingJoinQueueWithParams(MatchmakingJoinQueueRequest request)
{
if (!IsConnected.Value)
return Task.CompletedTask;
return Task.FromResult(new MatchmakingJoinQueueResponse());

Debug.Assert(connection != null);
return connection.InvokeAsync(nameof(IMatchmakingServer.MatchmakingJoinQueue), poolId);
return connection.InvokeAsync<MatchmakingJoinQueueResponse>(nameof(IMatchmakingServer.MatchmakingJoinQueueWithParams), request);
}

public override Task MatchmakingLeaveQueue()
Expand Down
3 changes: 3 additions & 0 deletions osu.Game/Online/Rooms/MultiplayerScore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ public class MultiplayerScore
[JsonProperty("total_score")]
public long TotalScore { get; set; }

[JsonProperty("total_score_without_mods")]
public long TotalScoreWithoutMods { get; set; }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be aware that due to intersecting concerns there may be a friction point with ppy/osu-web#13101 here.

Declaring this as non-nullable long may not fly because if the above PR goes in, then lazer scores without mods will have this set to zero. This matters for the read side, as this structure appears to be used both for reading from API as well as writing to it.


[JsonProperty("accuracy")]
public double Accuracy { get; set; }

Expand Down
44 changes: 30 additions & 14 deletions osu.Game/Online/Spectator/SpectatorScoreProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;

namespace osu.Game.Online.Spectator
{
Expand All @@ -24,11 +23,24 @@ namespace osu.Game.Online.Spectator
/// </summary>
public partial class SpectatorScoreProcessor : Component
{
/// <summary>
/// Whether to use the the total score without mods for display purposes.
/// </summary>
public bool UseTotalScoreWithoutMods { get; set; }

/// <summary>
/// The current total score.
/// </summary>
public readonly BindableLong TotalScore = new BindableLong { MinValue = 0 };

/// <summary>
/// The total number of points awarded for the score without including mod multipliers.
/// </summary>
/// <remarks>
/// The purpose of this property is to enable future lossless rebalances of mod multipliers.
/// </remarks>
public readonly BindableLong TotalScoreWithoutMods = new BindableLong { MinValue = 0 };

/// <summary>
/// The current accuracy.
/// </summary>
Expand All @@ -52,9 +64,12 @@ public partial class SpectatorScoreProcessor : Component
/// <summary>
/// The applied <see cref="Mod"/>s.
/// </summary>
public IReadOnlyList<Mod> Mods => scoreInfo?.Mods ?? Array.Empty<Mod>();
public IReadOnlyList<Mod> Mods => Score?.Mods ?? Array.Empty<Mod>();

public Func<ScoringMode, long> GetDisplayScore => mode => scoreInfo?.GetDisplayScore(mode) ?? 0;
/// <summary>
/// The score.
/// </summary>
public ScoreInfo? Score { get; private set; }

private IClock? referenceClock;

Expand All @@ -78,7 +93,6 @@ public IClock ReferenceClock
private readonly int userId;

private SpectatorState? spectatorState;
private ScoreInfo? scoreInfo;

public SpectatorScoreProcessor(int userId)
{
Expand All @@ -101,13 +115,13 @@ private void onSpectatorStatesChanged(object? sender, NotifyDictionaryChangedEve
{
if (!spectatorStates.TryGetValue(userId, out var userState) || userState.BeatmapID == null || userState.RulesetID == null)
{
scoreInfo = null;
Score = null;
spectatorState = null;
replayFrames.Clear();
return;
}

if (scoreInfo != null)
if (Score != null)
return;

RulesetInfo? rulesetInfo = rulesetStore.GetRuleset(userState.RulesetID.Value);
Expand All @@ -117,7 +131,7 @@ private void onSpectatorStatesChanged(object? sender, NotifyDictionaryChangedEve
Ruleset ruleset = rulesetInfo.CreateInstance();

spectatorState = userState;
scoreInfo = new ScoreInfo
Score = new ScoreInfo
{
Ruleset = rulesetInfo,
Mods = userState.Mods.Select(m => m.ToMod(ruleset)).ToArray()
Expand All @@ -131,7 +145,7 @@ private void onNewFrames(int incomingUserId, FrameDataBundle bundle)

Schedule(() =>
{
if (scoreInfo == null)
if (Score == null)
return;

replayFrames.Add(new TimedFrame(bundle.Frames.First().Time, bundle.Header));
Expand All @@ -141,7 +155,7 @@ private void onNewFrames(int incomingUserId, FrameDataBundle bundle)

public void UpdateScore()
{
if (scoreInfo == null || replayFrames.Count == 0)
if (Score == null || replayFrames.Count == 0)
return;

Debug.Assert(spectatorState != null);
Expand All @@ -154,16 +168,18 @@ public void UpdateScore()
TimedFrame frame = replayFrames[frameIndex];
Debug.Assert(frame.Header != null);

scoreInfo.Accuracy = frame.Header.Accuracy;
scoreInfo.MaxCombo = frame.Header.MaxCombo;
scoreInfo.Statistics = frame.Header.Statistics;
scoreInfo.MaximumStatistics = spectatorState.MaximumStatistics;
scoreInfo.TotalScore = frame.Header.TotalScore;
Score.Accuracy = frame.Header.Accuracy;
Score.MaxCombo = frame.Header.MaxCombo;
Score.Statistics = frame.Header.Statistics;
Score.MaximumStatistics = spectatorState.MaximumStatistics;
Score.TotalScore = frame.Header.TotalScore;
Score.TotalScoreWithoutMods = frame.Header.TotalScoreWithoutMods ?? 0;

Accuracy.Value = frame.Header.Accuracy;
Combo.Value = frame.Header.Combo;
HighestCombo.Value = frame.Header.MaxCombo;
TotalScore.Value = frame.Header.TotalScore;
TotalScoreWithoutMods.Value = frame.Header.TotalScoreWithoutMods ?? 0;
}

protected override void Dispose(bool isDisposing)
Expand Down
7 changes: 6 additions & 1 deletion osu.Game/Rulesets/Scoring/ScoreProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ public partial class ScoreProcessor : JudgementProcessor
/// <remarks>
/// Should only be disabled for special cases.
/// When disabled, <see cref="JudgementProcessor.RevertResult"/> cannot be used.</remarks>
internal bool TrackHitEvents = true;
internal bool TrackHitEvents { get; set; } = true;

/// <summary>
/// Whether to use the the total score without mods for display purposes.
/// </summary>
internal bool UseTotalScoreWithoutMods { get; set; }
Comment thread
bdach marked this conversation as resolved.

/// <summary>
/// Invoked when this <see cref="ScoreProcessor"/> was reset from a replay frame.
Expand Down
27 changes: 22 additions & 5 deletions osu.Game/Scoring/Legacy/ScoreInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,42 @@
using System.Linq;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Rooms;
using osu.Game.Online.Spectator;
using osu.Game.Rulesets.Scoring;

namespace osu.Game.Scoring.Legacy
{
public static class ScoreInfoExtensions
{
public static long GetDisplayScore(this ScoreProcessor scoreProcessor, ScoringMode mode)
=> getDisplayScore(scoreProcessor.Ruleset.RulesetInfo.OnlineID, scoreProcessor.TotalScore.Value, mode, scoreProcessor.MaximumStatistics);
{
if (scoreProcessor.UseTotalScoreWithoutMods)
return GetDisplayScore(scoreProcessor.Ruleset.RulesetInfo.OnlineID, scoreProcessor.TotalScoreWithoutMods.Value, mode, scoreProcessor.MaximumStatistics);

return GetDisplayScore(scoreProcessor.Ruleset.RulesetInfo.OnlineID, scoreProcessor.TotalScore.Value, mode, scoreProcessor.MaximumStatistics);
}

public static long GetDisplayScore(this SpectatorScoreProcessor scoreProcessor, ScoringMode mode)
Comment thread
bdach marked this conversation as resolved.
{
if (scoreProcessor.Score is not ScoreInfo score)
return 0;

if (scoreProcessor.UseTotalScoreWithoutMods)
return GetDisplayScore(score.RulesetID, score.TotalScoreWithoutMods, mode, score.MaximumStatistics);

return GetDisplayScore(score.RulesetID, score.TotalScore, mode, score.MaximumStatistics);
}

public static long GetDisplayScore(this ScoreInfo scoreInfo, ScoringMode mode)
=> getDisplayScore(scoreInfo.Ruleset.OnlineID, scoreInfo.TotalScore, mode, scoreInfo.MaximumStatistics);
=> GetDisplayScore(scoreInfo.Ruleset.OnlineID, scoreInfo.TotalScore, mode, scoreInfo.MaximumStatistics);

public static long GetDisplayScore(this SoloScoreInfo soloScoreInfo, ScoringMode mode)
=> getDisplayScore(soloScoreInfo.RulesetID, soloScoreInfo.TotalScore, mode, soloScoreInfo.MaximumStatistics);
=> GetDisplayScore(soloScoreInfo.RulesetID, soloScoreInfo.TotalScore, mode, soloScoreInfo.MaximumStatistics);

public static long GetDisplayScore(this MultiplayerScore multiplayerScore, ScoringMode mode)
=> getDisplayScore(multiplayerScore.RulesetId, multiplayerScore.TotalScore, mode, multiplayerScore.MaximumStatistics);
=> GetDisplayScore(multiplayerScore.RulesetId, multiplayerScore.TotalScore, mode, multiplayerScore.MaximumStatistics);

private static long getDisplayScore(int rulesetId, long score, ScoringMode mode, IReadOnlyDictionary<HitResult, int> maximumStatistics)
public static long GetDisplayScore(int rulesetId, long score, ScoringMode mode, IReadOnlyDictionary<HitResult, int> maximumStatistics)
{
if (mode == ScoringMode.Standardised)
return score;
Expand Down
16 changes: 13 additions & 3 deletions osu.Game/Screens/OnlinePlay/Matchmaking/Queue/QueueController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// See the LICENCE file in the repository root for full licence text.

using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Allocation;
using osu.Framework.Audio;
Expand All @@ -15,13 +17,15 @@
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Localisation;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Matchmaking;
using osu.Game.Online.Matchmaking.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Online.Rooms;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets.Mods;
using osu.Game.Screens.OnlinePlay.Matchmaking.Intro;

namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
Expand All @@ -36,6 +40,7 @@ public partial class QueueController : Component
{
public readonly Bindable<ScreenQueue.MatchmakingScreenState> CurrentState = new Bindable<ScreenQueue.MatchmakingScreenState>();
public readonly Bindable<MatchmakingPool?> SelectedPool = new Bindable<MatchmakingPool?>();
public readonly Bindable<IReadOnlyList<Mod>> SelectedMods = new Bindable<IReadOnlyList<Mod>>([]);

/// <summary>
/// Timer since the queue was joined.
Expand Down Expand Up @@ -74,13 +79,18 @@ protected override void LoadComplete()
/// Joins the matchmaking queue.
/// </summary>
/// <param name="pool">The pool to join.</param>
public void JoinQueue(MatchmakingPool pool)
/// <param name="mods">The requested mods.</param>
public void JoinQueue(MatchmakingPool pool, Mod[] mods)
{
lastDuelUser = null;
lastDuelPool = null;
QueueTimer.Restart();

client.MatchmakingJoinQueue(pool.Id).FireAndForget();
client.MatchmakingJoinQueueWithParams(new MatchmakingJoinQueueRequest
{
PoolId = pool.Id,
Mods = mods.Select(m => new APIMod(m)).ToArray()
}).FireAndForget();
}

/// <summary>
Expand Down Expand Up @@ -129,7 +139,7 @@ public void RejoinQueue()
if (lastDuelUser != null && lastDuelPool != null)
IssueDuel(lastDuelPool, lastDuelUser.Value);
else if (SelectedPool.Value != null)
JoinQueue(SelectedPool.Value);
JoinQueue(SelectedPool.Value, SelectedMods.Value.ToArray());
}

/// <summary>
Expand Down
Loading
Loading