From b5877bc10c22c438dacd959c7fc857709efa80cf Mon Sep 17 00:00:00 2001 From: Josh Date: Tue, 10 Jan 2023 17:36:43 -0600 Subject: [PATCH] Remove duplicate scores (#622) * Remove duplicate scores * Optimize score migration --- .../Controllers/Slots/ScoreController.cs | 52 ++++++++----------- .../Pages/Partials/LeaderboardPartial.cshtml | 10 +++- .../CleanupDuplicateScoresMigration.cs | 48 +++++++++++++++++ 3 files changed, 78 insertions(+), 32 deletions(-) create mode 100644 ProjectLighthouse/Administration/Maintenance/MigrationTasks/CleanupDuplicateScoresMigration.cs diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs index ce8bb97b..fda3c09a 100644 --- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs +++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs @@ -29,7 +29,7 @@ public class ScoreController : ControllerBase [HttpPost("scoreboard/{slotType}/{id:int}")] [HttpPost("scoreboard/{slotType}/{id:int}/{childId:int}")] - public async Task SubmitScore(string slotType, int id, int childId, [FromQuery] bool lbp1 = false, [FromQuery] bool lbp2 = false, [FromQuery] bool lbp3 = false) + public async Task SubmitScore(string slotType, int id, int childId) { GameToken token = this.GetToken(); @@ -49,7 +49,7 @@ public class ScoreController : ControllerBase } // This only seems to happens on lbp2 versus levels, not sure why - if(score.PlayerIdCollection.Contains(':')) + if (score.PlayerIdCollection.Contains(':')) score.PlayerIdCollection = score.PlayerIdCollection.Replace(':', ','); if (score.PlayerIds.Length == 0) @@ -111,42 +111,34 @@ public class ScoreController : ControllerBase case GameVersion.LittleBigPlanet3: slot.PlaysLBP3Complete++; break; - case GameVersion.LittleBigPlanetPSP: break; - case GameVersion.Unknown: break; + case GameVersion.LittleBigPlanetPSP: + case GameVersion.Unknown: default: throw new ArgumentOutOfRangeException(); } - // Submit scores from all players in lobby - foreach (string player in score.PlayerIds) + Score playerScore = new() { - List players = new(); - players.Add(player); // make sure this player is first - players.AddRange(score.PlayerIds.Where(p => p != player)); + PlayerIdCollection = string.Join(',', score.PlayerIds), + Type = score.Type, + Points = score.Points, + SlotId = score.SlotId, + ChildSlotId = score.ChildSlotId, + }; - Score playerScore = new() - { - PlayerIdCollection = string.Join(',', players), - Type = score.Type, - Points = score.Points, - SlotId = score.SlotId, - ChildSlotId = score.ChildSlotId, - }; - - IQueryable existingScore = this.database.Scores.Where(s => s.SlotId == playerScore.SlotId) + IQueryable existingScore = this.database.Scores.Where(s => s.SlotId == playerScore.SlotId) .Where(s => s.ChildSlotId == 0 || s.ChildSlotId == childId) .Where(s => s.PlayerIdCollection == playerScore.PlayerIdCollection) .Where(s => s.Type == playerScore.Type); - if (existingScore.Any()) - { - Score first = existingScore.First(s => s.SlotId == playerScore.SlotId); - playerScore.ScoreId = first.ScoreId; - playerScore.Points = Math.Max(first.Points, playerScore.Points); - this.database.Entry(first).CurrentValues.SetValues(playerScore); - } - else - { - this.database.Scores.Add(playerScore); - } + if (existingScore.Any()) + { + Score first = existingScore.First(s => s.SlotId == playerScore.SlotId); + playerScore.ScoreId = first.ScoreId; + playerScore.Points = Math.Max(first.Points, playerScore.Points); + this.database.Entry(first).CurrentValues.SetValues(playerScore); + } + else + { + this.database.Scores.Add(playerScore); } await this.database.SaveChangesAsync(); diff --git a/ProjectLighthouse.Servers.Website/Pages/Partials/LeaderboardPartial.cshtml b/ProjectLighthouse.Servers.Website/Pages/Partials/LeaderboardPartial.cshtml index 0418b496..604e1a1a 100644 --- a/ProjectLighthouse.Servers.Website/Pages/Partials/LeaderboardPartial.cshtml +++ b/ProjectLighthouse.Servers.Website/Pages/Partials/LeaderboardPartial.cshtml @@ -42,11 +42,17 @@ @for (int j = 0; j < playerIds.Length; j++) { User? user = await database.Users.FirstOrDefaultAsync(u => u.Username == playerIds[j]); - if (user == null) continue;
- @await user.ToLink(Html, ViewData, language, timeZone) + @if (user != null) + { + @await user.ToLink(Html, ViewData, language, timeZone) + } + else + { +

@playerIds[j]

+ }
} diff --git a/ProjectLighthouse/Administration/Maintenance/MigrationTasks/CleanupDuplicateScoresMigration.cs b/ProjectLighthouse/Administration/Maintenance/MigrationTasks/CleanupDuplicateScoresMigration.cs new file mode 100644 index 00000000..e29bee1f --- /dev/null +++ b/ProjectLighthouse/Administration/Maintenance/MigrationTasks/CleanupDuplicateScoresMigration.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using LBPUnion.ProjectLighthouse.Logging; +using LBPUnion.ProjectLighthouse.PlayerData; + +namespace LBPUnion.ProjectLighthouse.Administration.Maintenance.MigrationTasks; + +public class CleanupDuplicateScoresMigration : IMigrationTask +{ + public string Name() => "Cleanup duplicate scores"; + + public async Task Run(Database database) + { + List duplicateScoreIds = new(); + // The original score should have the lowest score id + foreach (Score score in database.Scores.OrderBy(s => s.ScoreId) + .ToList() + .Where(score => !duplicateScoreIds.Contains(score.ScoreId))) + { + foreach (Score other in database.Scores.Where(s => + s.Points == score.Points && + s.Type == score.Type && + s.SlotId == score.SlotId && + s.ScoreId != score.ScoreId && + s.ChildSlotId == score.ChildSlotId && + s.ScoreId > score.ScoreId)) + { + if (score.PlayerIds.Length != other.PlayerIds.Length) + continue; + + HashSet hashSet = new(score.PlayerIds); + + if (!other.PlayerIds.All(hashSet.Contains)) continue; + + Logger.Info($"Removing score with id {other.ScoreId}, slotId={other.SlotId} main='{score.PlayerIdCollection}', duplicate={other.PlayerIdCollection}", LogArea.Score); + database.Scores.Remove(other); + duplicateScoreIds.Add(other.ScoreId); + } + } + + Logger.Info($"Removed a total of {duplicateScoreIds.Count} duplicate scores", LogArea.Score); + await database.SaveChangesAsync(); + + return true; + } + +} \ No newline at end of file