diff --git a/osu.Game/Database/BackgroundDataStoreProcessor.cs b/osu.Game/Database/BackgroundDataStoreProcessor.cs index 324d699e7c..1e44141819 100644 --- a/osu.Game/Database/BackgroundDataStoreProcessor.cs +++ b/osu.Game/Database/BackgroundDataStoreProcessor.cs @@ -355,8 +355,7 @@ private void convertLegacyTotalScoreToStandardised() realmAccess.Write(r => { ScoreInfo s = r.Find(id)!; - // TODO: ensure that this is also updating rank (as it will set TotalScoreVersion to latest). - StandardisedScoreMigrationTools.UpdateFromLegacy(s, beatmapManager); + StandardisedScoreMigrationTools.UpdateFromLegacy(s, beatmapManager.GetWorkingBeatmap(s.BeatmapInfo)); s.TotalScoreVersion = LegacyScoreEncoder.LATEST_VERSION; }); @@ -412,8 +411,7 @@ private void upgradeScoreRanks() realmAccess.Write(r => { ScoreInfo s = r.Find(id)!; - // TODO: uncomment when ready - // s.Rank = StandardisedScoreMigrationTools.ComputeRank(s, beatmapManager); + s.Rank = StandardisedScoreMigrationTools.ComputeRank(s); }); ++processedCount; diff --git a/osu.Game/Database/StandardisedScoreMigrationTools.cs b/osu.Game/Database/StandardisedScoreMigrationTools.cs index 4221ab93f1..d62d4a905a 100644 --- a/osu.Game/Database/StandardisedScoreMigrationTools.cs +++ b/osu.Game/Database/StandardisedScoreMigrationTools.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using osu.Framework.Logging; using osu.Game.Beatmaps; @@ -235,39 +234,49 @@ static int numericScoreFor(HitResult result) /// Updates a legacy to standardised scoring. /// /// The score to update. - /// A used for lookups. - public static void UpdateFromLegacy(ScoreInfo score, BeatmapManager beatmaps) + /// The applicable for this score. + public static void UpdateFromLegacy(ScoreInfo score, WorkingBeatmap beatmap) { - score.TotalScore = convertFromLegacyTotalScore(score, beatmaps); - score.Accuracy = ComputeAccuracy(score); + var ruleset = score.Ruleset.CreateInstance(); + var scoreProcessor = ruleset.CreateScoreProcessor(); + + score.TotalScore = convertFromLegacyTotalScore(score, ruleset, beatmap); + score.Accuracy = computeAccuracy(score, scoreProcessor); + score.Rank = computeRank(score, scoreProcessor); } /// /// Updates a legacy to standardised scoring. /// + /// + /// This overload is intended for server-side flows. + /// See: https://github.com/ppy/osu-queue-score-statistics/blob/3681e92ac91c6c61922094bdbc7e92e6217dd0fc/osu.Server.Queues.ScoreStatisticsProcessor/Commands/Queue/BatchInserter.cs + /// /// The score to update. + /// The in which the score was set. /// The beatmap difficulty. /// The legacy scoring attributes for the beatmap which the score was set on. - public static void UpdateFromLegacy(ScoreInfo score, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes) + public static void UpdateFromLegacy(ScoreInfo score, Ruleset ruleset, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes) { - score.TotalScore = convertFromLegacyTotalScore(score, difficulty, attributes); - score.Accuracy = ComputeAccuracy(score); + var scoreProcessor = ruleset.CreateScoreProcessor(); + + score.TotalScore = convertFromLegacyTotalScore(score, ruleset, difficulty, attributes); + score.Accuracy = computeAccuracy(score, scoreProcessor); + score.Rank = computeRank(score, scoreProcessor); } /// /// Converts from to the new standardised scoring of . /// /// The score to convert the total score of. - /// A used for lookups. + /// The in which the score was set. + /// The applicable for this score. /// The standardised total score. - private static long convertFromLegacyTotalScore(ScoreInfo score, BeatmapManager beatmaps) + private static long convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, WorkingBeatmap beatmap) { if (!score.IsLegacyScore) return score.TotalScore; - WorkingBeatmap beatmap = beatmaps.GetWorkingBeatmap(score.BeatmapInfo); - Ruleset ruleset = score.Ruleset.CreateInstance(); - if (ruleset is not ILegacyRuleset legacyRuleset) return score.TotalScore; @@ -283,27 +292,28 @@ private static long convertFromLegacyTotalScore(ScoreInfo score, BeatmapManager ILegacyScoreSimulator sv1Simulator = legacyRuleset.CreateLegacyScoreSimulator(); LegacyScoreAttributes attributes = sv1Simulator.Simulate(beatmap, playableBeatmap); - return convertFromLegacyTotalScore(score, LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap.Beatmap), attributes); + return convertFromLegacyTotalScore(score, ruleset, LegacyBeatmapConversionDifficultyInfo.FromBeatmap(beatmap.Beatmap), attributes); } /// /// Converts from to the new standardised scoring of . /// /// The score to convert the total score of. + /// The in which the score was set. /// The beatmap difficulty. /// The legacy scoring attributes for the beatmap which the score was set on. /// The standardised total score. - private static long convertFromLegacyTotalScore(ScoreInfo score, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes) + private static long convertFromLegacyTotalScore(ScoreInfo score, Ruleset ruleset, LegacyBeatmapConversionDifficultyInfo difficulty, LegacyScoreAttributes attributes) { if (!score.IsLegacyScore) return score.TotalScore; - Debug.Assert(score.LegacyTotalScore != null); - - Ruleset ruleset = score.Ruleset.CreateInstance(); if (ruleset is not ILegacyRuleset legacyRuleset) return score.TotalScore; + // ensure legacy total score is saved for later. + score.LegacyTotalScore = score.TotalScore; + double legacyModMultiplier = legacyRuleset.CreateLegacyScoreSimulator().GetLegacyScoreMultiplier(score.Mods, difficulty); int maximumLegacyAccuracyScore = attributes.AccuracyScore; long maximumLegacyComboScore = (long)Math.Round(attributes.ComboScore * legacyModMultiplier); @@ -584,11 +594,10 @@ double estimateDroppedComboScoreAfterMiss(int lengthOfComboAfterMiss) } } - public static double ComputeAccuracy(ScoreInfo scoreInfo) - { - Ruleset ruleset = scoreInfo.Ruleset.CreateInstance(); - ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor(); + public static double ComputeAccuracy(ScoreInfo scoreInfo) => computeAccuracy(scoreInfo, scoreInfo.Ruleset.CreateInstance().CreateScoreProcessor()); + private static double computeAccuracy(ScoreInfo scoreInfo, ScoreProcessor scoreProcessor) + { int baseScore = scoreInfo.Statistics.Where(kvp => kvp.Key.AffectsAccuracy()) .Sum(kvp => kvp.Value * scoreProcessor.GetBaseScoreForResult(kvp.Key)); int maxBaseScore = scoreInfo.MaximumStatistics.Where(kvp => kvp.Key.AffectsAccuracy()) @@ -597,10 +606,11 @@ public static double ComputeAccuracy(ScoreInfo scoreInfo) return maxBaseScore == 0 ? 1 : baseScore / (double)maxBaseScore; } - public static ScoreRank ComputeRank(ScoreInfo scoreInfo) + public static ScoreRank ComputeRank(ScoreInfo scoreInfo) => computeRank(scoreInfo, scoreInfo.Ruleset.CreateInstance().CreateScoreProcessor()); + + private static ScoreRank computeRank(ScoreInfo scoreInfo, ScoreProcessor scoreProcessor) { - Ruleset ruleset = scoreInfo.Ruleset.CreateInstance(); - var rank = ruleset.CreateScoreProcessor().RankFromScore(scoreInfo.Accuracy, scoreInfo.Statistics); + var rank = scoreProcessor.RankFromScore(scoreInfo.Accuracy, scoreInfo.Statistics); foreach (var mod in scoreInfo.Mods.OfType()) rank = mod.AdjustRank(rank, scoreInfo.Accuracy); diff --git a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs index be704ca18b..c12e8b8474 100644 --- a/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs +++ b/osu.Game/Scoring/Legacy/LegacyScoreDecoder.cs @@ -134,8 +134,7 @@ public Score Parse(Stream stream) } PopulateMaximumStatistics(score.ScoreInfo, workingBeatmap); - score.ScoreInfo.Accuracy = StandardisedScoreMigrationTools.ComputeAccuracy(score.ScoreInfo); - score.ScoreInfo.Rank = StandardisedScoreMigrationTools.ComputeRank(score.ScoreInfo); + StandardisedScoreMigrationTools.UpdateFromLegacy(score.ScoreInfo, workingBeatmap); // before returning for database import, we must restore the database-sourced BeatmapInfo. // if not, the clone operation in GetPlayableBeatmap will cause a dereference and subsequent database exception. @@ -342,18 +341,6 @@ public static void PopulateLegacyAccuracyAndRank(ScoreInfo score) } } - private void populateLazerAccuracyAndRank(ScoreInfo scoreInfo) - { - scoreInfo.Accuracy = StandardisedScoreMigrationTools.ComputeAccuracy(scoreInfo); - - var rank = currentRuleset.CreateScoreProcessor().RankFromScore(scoreInfo.Accuracy, scoreInfo.Statistics); - - foreach (var mod in scoreInfo.Mods.OfType()) - rank = mod.AdjustRank(rank, scoreInfo.Accuracy); - - scoreInfo.Rank = rank; - } - private void readLegacyReplay(Replay replay, StreamReader reader) { float lastTime = beatmapOffset; diff --git a/osu.Game/Scoring/ScoreImporter.cs b/osu.Game/Scoring/ScoreImporter.cs index afa522b253..768c28cc38 100644 --- a/osu.Game/Scoring/ScoreImporter.cs +++ b/osu.Game/Scoring/ScoreImporter.cs @@ -100,11 +100,6 @@ protected override void Populate(ScoreInfo model, ArchiveReader? archive, Realm // this requires: max combo, statistics, max statistics (where available), and mods to already be populated on the score. if (StandardisedScoreMigrationTools.ShouldMigrateToNewStandardised(model)) model.TotalScore = StandardisedScoreMigrationTools.GetNewStandardised(model); - else if (model.IsLegacyScore) - { - model.LegacyTotalScore = model.TotalScore; - StandardisedScoreMigrationTools.UpdateFromLegacy(model, beatmaps()); - } } // Very naive local caching to improve performance of large score imports (where the username is usually the same for most or all scores).