mirror of
https://github.com/ppy/osu.git
synced 2026-05-18 12:00:22 +08:00
Merge pull request #34904 from bdach/local-rank-includes-unproven-scores
Treat guest user scores & scores of unknown users as the local user's
This commit is contained in:
@@ -10,6 +10,8 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Select.Carousel;
|
||||
@@ -161,5 +163,53 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddUntilStep("SS rank displayed", () => topLocalRank.DisplayedRank == ScoreRank.X);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGuestScore()
|
||||
{
|
||||
AddStep("Add score for guest user", () =>
|
||||
{
|
||||
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
|
||||
|
||||
testScoreInfo.User = new GuestUser();
|
||||
testScoreInfo.Rank = ScoreRank.B;
|
||||
|
||||
scoreManager.Import(testScoreInfo);
|
||||
});
|
||||
|
||||
AddUntilStep("B rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.B));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnknownUserScore()
|
||||
{
|
||||
AddStep("Add score for unknown user", () =>
|
||||
{
|
||||
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
|
||||
|
||||
testScoreInfo.User = new APIUser { Username = "AAA", };
|
||||
testScoreInfo.Rank = ScoreRank.S;
|
||||
|
||||
scoreManager.Import(testScoreInfo);
|
||||
});
|
||||
|
||||
AddUntilStep("S rank displayed", () => topLocalRank.DisplayedRank, () => Is.EqualTo(ScoreRank.S));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAnotherUserScore()
|
||||
{
|
||||
AddStep("Add score for not-current user", () =>
|
||||
{
|
||||
var testScoreInfo = TestResources.CreateTestScoreInfo(importedBeatmap);
|
||||
|
||||
testScoreInfo.User = new APIUser { Username = "notme", Id = 43, };
|
||||
testScoreInfo.Rank = ScoreRank.S;
|
||||
|
||||
scoreManager.Import(testScoreInfo);
|
||||
});
|
||||
|
||||
AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank, () => Is.Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using Realms;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
@@ -64,5 +67,23 @@ namespace osu.Game.Scoring
|
||||
/// <param name="score">The <see cref="ScoreInfo"/> to compute the maximum achievable combo for.</param>
|
||||
/// <returns>The maximum achievable combo.</returns>
|
||||
public static int GetMaximumAchievableCombo(this ScoreInfo score) => score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Sum(kvp => kvp.Value);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a realm filter that returns all scores that belong to the user with the given <paramref name="userId"/>.
|
||||
/// <see langword="null"/> <paramref name="userId"/> (for guests) is supported.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All guest scores (with user ID of <see cref="APIUser.SYSTEM_USER_ID"/>),
|
||||
/// as well as scores of unknown provenance (with default user ID of 1, see <see cref="APIUser.OnlineID"/>),
|
||||
/// will be treated as if they belong to the local user.
|
||||
/// This may not be necessarily considered fully correct in some circumstances, but in most cases it is the desired effect.
|
||||
/// </remarks>
|
||||
public static IQueryable<ScoreInfo> GetAllLocalScoresForUser(this Realm realm, int? userId)
|
||||
{
|
||||
return realm.All<ScoreInfo>()
|
||||
.Filter($@"({nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0 || {nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} <= 1)"
|
||||
+ $@" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
|
||||
+ $@" && {nameof(ScoreInfo.DeletePending)} == false", userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ using osu.Game.Extensions;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Placeholders;
|
||||
using osu.Game.Scoring;
|
||||
@@ -246,11 +245,8 @@ namespace osu.Game.Screens.Ranking.Statistics
|
||||
// We may want to iterate on the following conditions further in the future
|
||||
|
||||
var localUserScore = AchievedScore ?? realm.Run(r =>
|
||||
r.All<ScoreInfo>()
|
||||
.Filter($@"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
|
||||
+ $@" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
|
||||
+ $@" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
|
||||
+ $@" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, newScore.BeatmapInfo.ID, newScore.BeatmapInfo.Ruleset.ShortName)
|
||||
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
|
||||
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0", newScore.BeatmapInfo.ID)
|
||||
.AsEnumerable()
|
||||
.OrderByDescending(score => score.Ruleset.MatchesOnlineID(newScore.BeatmapInfo.Ruleset))
|
||||
.ThenByDescending(score => score.Rank)
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets;
|
||||
@@ -59,12 +58,9 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
scoreSubscription?.Dispose();
|
||||
scoreSubscription = realm.RegisterForNotifications(r =>
|
||||
r.All<ScoreInfo>()
|
||||
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
|
||||
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
|
||||
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmapInfo.ID, ruleset.Value.ShortName),
|
||||
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
|
||||
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1", beatmapInfo.ID, ruleset.Value.ShortName),
|
||||
localScoresChanged);
|
||||
}, true);
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Carousel;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Select;
|
||||
@@ -758,11 +757,8 @@ namespace osu.Game.Screens.SelectV2
|
||||
{
|
||||
var topRankMapping = new Dictionary<Guid, ScoreRank>();
|
||||
|
||||
var allLocalScores = r.All<ScoreInfo>()
|
||||
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1"
|
||||
+ $" && {nameof(ScoreInfo.DeletePending)} == false", criteria.LocalUserId, criteria.Ruleset?.ShortName)
|
||||
var allLocalScores = r.GetAllLocalScoresForUser(criteria.LocalUserId)
|
||||
.Filter($@"{nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $0", criteria.Ruleset?.ShortName)
|
||||
.OrderByDescending(s => s.TotalScore)
|
||||
.ThenBy(s => s.Date);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.Leaderboards;
|
||||
using osu.Game.Rulesets;
|
||||
@@ -78,12 +77,9 @@ namespace osu.Game.Screens.SelectV2
|
||||
return;
|
||||
|
||||
scoreSubscription = realm.RegisterForNotifications(r =>
|
||||
r.All<ScoreInfo>()
|
||||
.Filter($"{nameof(ScoreInfo.User)}.{nameof(RealmUser.OnlineID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $1"
|
||||
+ $" && {nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.Hash)} == {nameof(ScoreInfo.BeatmapHash)}"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $2"
|
||||
+ $" && {nameof(ScoreInfo.DeletePending)} == false", api.LocalUser.Value.Id, beatmap.ID, ruleset.Value.ShortName),
|
||||
r.GetAllLocalScoresForUser(api.LocalUser.Value.Id)
|
||||
.Filter($@"{nameof(ScoreInfo.BeatmapInfo)}.{nameof(BeatmapInfo.ID)} == $0"
|
||||
+ $" && {nameof(ScoreInfo.Ruleset)}.{nameof(RulesetInfo.ShortName)} == $1", beatmap.ID, ruleset.Value.ShortName),
|
||||
localScoresChanged);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user