Skip to content

Commit 16ea4b2

Browse files
authored
Fix level friend leaderboards, other level score query optimizations (#862)
2 parents 8cc04d3 + 82d312d commit 16ea4b2

File tree

4 files changed

+33
-31
lines changed

4 files changed

+33
-31
lines changed

Refresh.Database/GameDatabaseContext.Leaderboard.cs

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public GameScore SubmitScore(ISerializedScore score, GameUser user, GameLevel le
4040

4141
#region Notifications
4242

43-
IEnumerable<ScoreWithRank> rankedScores = GetRankedScoresAroundScore(newScore, 3).ToList();
43+
IEnumerable<ScoreWithRank> rankedScores = GetRankedScoresAroundScore(newScore, 3).Items;
4444
ScoreWithRank? rankOne = rankedScores.FirstOrDefault(s => s.rank == 1);
4545
ScoreWithRank? rankTwo = rankedScores.FirstOrDefault(s => s.rank == 2);
4646
if (rankOne != null && rankTwo != null &&
@@ -65,53 +65,51 @@ public GameScore SubmitScore(ISerializedScore score, GameUser user, GameLevel le
6565
public DatabaseList<GameScore> GetTopScoresForLevel(GameLevel level, int count, int skip, byte type, bool showDuplicates = false)
6666
{
6767
IEnumerable<GameScore> scores = this.GameScoresIncluded
68-
.Where(s => s.ScoreType == type && s.Level == level)
69-
.OrderByDescending(s => s.Score)
70-
.AsEnumerableIfRealm();
68+
.Where(s => s.ScoreType == type && s.LevelId == level.LevelId)
69+
.OrderByDescending(s => s.Score);
7170

7271
if (!showDuplicates)
7372
scores = scores.DistinctBy(s => s.PlayerIds[0]);
7473

7574
return new DatabaseList<GameScore>(scores, skip, count);
7675
}
7776

78-
public IEnumerable<ScoreWithRank> GetRankedScoresAroundScore(GameScore score, int count)
77+
public DatabaseList<ScoreWithRank> GetRankedScoresAroundScore(GameScore score, int count)
7978
{
8079
if (count % 2 != 1) throw new ArgumentException("The number of scores must be odd.", nameof(count));
8180

8281
// this is probably REALLY fucking slow, and i probably shouldn't be trusted with LINQ anymore
8382

8483
List<GameScore> scores = this.GameScoresIncluded
85-
.Where(s => s.ScoreType == score.ScoreType && s.Level == score.Level)
84+
.Where(s => s.ScoreType == score.ScoreType && s.LevelId == score.LevelId)
8685
.OrderByDescending(s => s.Score)
87-
.AsEnumerable()
88-
.ToList();
89-
90-
scores = scores.DistinctBy(s => s.PlayerIds[0])
86+
.ToArray()
87+
.DistinctBy(s => s.PlayerIds[0])
9188
.ToList();
9289

93-
return scores.Select((s, i) => new ScoreWithRank(s, i + 1))
94-
.Skip(Math.Min(scores.Count, scores.IndexOf(score) - count / 2)) // center user's score around other scores
95-
.Take(count);
90+
return new
91+
(
92+
scores.Select((s, i) => new ScoreWithRank(s, i + 1)),
93+
Math.Min(scores.Count, scores.IndexOf(score) - count / 2), // center user's score around other scores
94+
count
95+
);
9696
}
9797

98-
public IEnumerable<ScoreWithRank> GetLevelTopScoresByFriends(GameUser user, GameLevel level, int count, byte type)
98+
public DatabaseList<ScoreWithRank> GetLevelTopScoresByFriends(GameUser user, GameLevel level, int count, byte scoreType)
9999
{
100100
IEnumerable<ObjectId> mutuals = this.GetUsersMutuals(user)
101-
.AsEnumerableIfRealm()
102-
.Select(u => u.UserId);
103-
104-
IEnumerable<GameScore> scores = this.GameScores
105-
.Where(s => s.ScoreType == type && s.Level == level)
101+
.Select(u => u.UserId)
102+
.Append(user.UserId);
103+
104+
IEnumerable<GameScore> scores = this.GameScoresIncluded
105+
.Where(s => s.ScoreType == scoreType && s.LevelId == level.LevelId)
106106
.OrderByDescending(s => s.Score)
107-
.AsEnumerableIfRealm()
107+
.ToArray()
108108
.DistinctBy(s => s.PlayerIds[0])
109109
//TODO: THIS CALL IS EXTREMELY INEFFECIENT!!! once we are in postgres land, figure out a way to do this effeciently
110-
.Where(s => s.PlayerIds.Any(p => p == user.UserId || mutuals.Contains(p)))
111-
.Take(10)
112-
.ToList();
110+
.Where(s => s.PlayerIds.Any(p => mutuals.Contains(p)));
113111

114-
return scores.Select((s, i) => new ScoreWithRank(s, i + 1));
112+
return new(scores.Select((s, i) => new ScoreWithRank(s, i + 1)), 0, count);
115113
}
116114

117115
[Pure]
@@ -173,7 +171,6 @@ public IEnumerable<GameUser> GetPlayersFromScore(GameScore score)
173171
{
174172
IEnumerable<ObjectId> playerIds = score.PlayerIds.Select(p => p);
175173
return this.GameUsersIncluded
176-
.AsEnumerableIfRealm()
177174
.Where(u => playerIds.Contains(u.UserId));
178175
}
179176

Refresh.Database/Models/Levels/Scores/GameScore.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ public partial class GameScore
1111
{
1212
[Key] public ObjectId ScoreId { get; set; } = ObjectId.GenerateNewId();
1313

14-
public TokenGame Game { get; set; }
14+
public TokenGame Game { get; set; }
1515
public TokenPlatform Platform { get; set; }
1616

17+
[Required] public int LevelId { get; set; }
1718
[Required] public GameLevel Level { get; set; }
1819
public DateTimeOffset ScoreSubmitted { get; set; }
1920

Refresh.Interfaces.Game/Endpoints/Levels/LeaderboardEndpoints.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ public Response GetUserScores(RequestContext context, GameUser user, GameDatabas
8787
{
8888
GameLevel? level = database.GetLevelByIdAndType(slotType, id);
8989
if (level == null) return null;
90-
91-
return SerializedScoreLeaderboardList.FromSubmittedEnumerable(database.GetLevelTopScoresByFriends(user, level, 10, body.Type), dataContext);
90+
91+
DatabaseList<ScoreWithRank>? scores = database.GetLevelTopScoresByFriends(user, level, 10, body.Type);
92+
return SerializedScoreLeaderboardList.FromSubmittedEnumerable(scores.Items, dataContext);
9293
}
9394

9495
[GameEndpoint("scoreboard/{slotType}/{id}", ContentType.Xml, HttpMethods.Post)]
@@ -125,10 +126,10 @@ public Response SubmitScore(RequestContext context, GameUser user, GameServerCon
125126

126127
GameScore score = database.SubmitScore(body, token, level);
127128

128-
IEnumerable<ScoreWithRank>? scores = database.GetRankedScoresAroundScore(score, 5);
129+
DatabaseList<ScoreWithRank>? scores = database.GetRankedScoresAroundScore(score, 5);
129130
Debug.Assert(scores != null);
130131

131-
return new Response(SerializedScoreLeaderboardList.FromSubmittedEnumerable(scores, dataContext), ContentType.Xml);
132+
return new Response(SerializedScoreLeaderboardList.FromSubmittedEnumerable(scores.Items.ToArray(), dataContext), ContentType.Xml);
132133
}
133134

134135
[GameEndpoint("topscores/{slotType}/{id}/{type}", ContentType.Xml)]
@@ -141,6 +142,8 @@ public Response GetTopScoresForLevel(RequestContext context, GameDatabaseContext
141142
if (level == null) return NotFound;
142143

143144
(int skip, int count) = context.GetPageData();
144-
return new Response(SerializedScoreList.FromSubmittedEnumerable(database.GetTopScoresForLevel(level, count, skip, (byte)type).Items.ToArrayIfPostgres(), dataContext, skip), ContentType.Xml);
145+
DatabaseList<GameScore>? scores = database.GetTopScoresForLevel(level, count, skip, (byte)type);
146+
147+
return new Response(SerializedScoreList.FromSubmittedEnumerable(scores.Items.ToArray(), dataContext, skip), ContentType.Xml);
145148
}
146149
}

RefreshTests.GameServer/Tests/Levels/ScoreLeaderboardTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ private void ScoreSegmentTest(int count, int expectedIndex, int leaderboardCount
317317
GameScore score = context.SubmitScore(submittedScore, 1, level, user, TokenGame.LittleBigPlanet2, TokenPlatform.PS3);
318318

319319
List<ObjectId> scores = context.Database.GetRankedScoresAroundScore(score, count)!
320+
.Items
320321
.Select(s => s.score.ScoreId)
321322
.ToList();
322323

0 commit comments

Comments
 (0)