Export and import `TotalScoreWithoutMods` to replays (or recalculate if it missing)

This commit is contained in:
Bartłomiej Dach 2024-04-17 09:08:15 +02:00
parent e0178802b8
commit 2f1a4cdaa4
No known key found for this signature in database
4 changed files with 94 additions and 8 deletions

View File

@ -412,6 +412,80 @@ public void AccuracyAndRankOfLazerScoreWithoutLegacyReplaySoloScoreInfoUsesBestE
});
}
[Test]
public void TestTotalScoreWithoutModsReadIfPresent()
{
var ruleset = new OsuRuleset().RulesetInfo;
var scoreInfo = TestResources.CreateTestScoreInfo(ruleset);
scoreInfo.Mods = new Mod[]
{
new OsuModDoubleTime { SpeedChange = { Value = 1.1 } }
};
scoreInfo.OnlineID = 123123;
scoreInfo.ClientVersion = "2023.1221.0";
scoreInfo.TotalScoreWithoutMods = 1_000_000;
scoreInfo.TotalScore = 1_020_000;
var beatmap = new TestBeatmap(ruleset);
var score = new Score
{
ScoreInfo = scoreInfo,
Replay = new Replay
{
Frames = new List<ReplayFrame>
{
new OsuReplayFrame(2000, OsuPlayfield.BASE_SIZE / 2, OsuAction.LeftButton)
}
}
};
var decodedAfterEncode = encodeThenDecode(LegacyBeatmapDecoder.LATEST_VERSION, score, beatmap);
Assert.Multiple(() =>
{
Assert.That(decodedAfterEncode.ScoreInfo.TotalScoreWithoutMods, Is.EqualTo(1_000_000));
Assert.That(decodedAfterEncode.ScoreInfo.TotalScore, Is.EqualTo(1_020_000));
});
}
[Test]
public void TestTotalScoreWithoutModsBackwardsPopulatedIfMissing()
{
var ruleset = new OsuRuleset().RulesetInfo;
var scoreInfo = TestResources.CreateTestScoreInfo(ruleset);
scoreInfo.Mods = new Mod[]
{
new OsuModDoubleTime { SpeedChange = { Value = 1.1 } }
};
scoreInfo.OnlineID = 123123;
scoreInfo.ClientVersion = "2023.1221.0";
scoreInfo.TotalScoreWithoutMods = 0;
scoreInfo.TotalScore = 1_020_000;
var beatmap = new TestBeatmap(ruleset);
var score = new Score
{
ScoreInfo = scoreInfo,
Replay = new Replay
{
Frames = new List<ReplayFrame>
{
new OsuReplayFrame(2000, OsuPlayfield.BASE_SIZE / 2, OsuAction.LeftButton)
}
}
};
var decodedAfterEncode = encodeThenDecode(LegacyBeatmapDecoder.LATEST_VERSION, score, beatmap);
Assert.Multiple(() =>
{
Assert.That(decodedAfterEncode.ScoreInfo.TotalScoreWithoutMods, Is.EqualTo(1_000_000));
Assert.That(decodedAfterEncode.ScoreInfo.TotalScore, Is.EqualTo(1_020_000));
});
}
private static Score encodeThenDecode(int beatmapVersion, Score score, TestBeatmap beatmap)
{
var encodeStream = new MemoryStream();

View File

@ -1113,14 +1113,7 @@ void convertOnlineIDs<T>() where T : RealmObject
case 41:
foreach (var score in migration.NewRealm.All<ScoreInfo>())
{
double modMultiplier = 1;
foreach (var mod in score.Mods)
modMultiplier *= mod.ScoreMultiplier;
score.TotalScoreWithoutMods = (long)Math.Round(score.TotalScore / modMultiplier);
}
LegacyScoreDecoder.PopulateTotalScoreWithoutMods(score);
break;
}

View File

@ -38,6 +38,9 @@ public class LegacyReplaySoloScoreInfo
[JsonProperty("client_version")]
public string ClientVersion = string.Empty;
[JsonProperty("total_score_without_mods")]
public long? TotalScoreWithoutMods { get; set; }
public static LegacyReplaySoloScoreInfo FromScore(ScoreInfo score) => new LegacyReplaySoloScoreInfo
{
OnlineID = score.OnlineID,
@ -45,6 +48,7 @@ public class LegacyReplaySoloScoreInfo
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(),
MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(),
ClientVersion = score.ClientVersion,
TotalScoreWithoutMods = score.TotalScoreWithoutMods > 0 ? score.TotalScoreWithoutMods : null,
};
}
}

View File

@ -129,6 +129,11 @@ public Score Parse(Stream stream)
score.ScoreInfo.MaximumStatistics = readScore.MaximumStatistics;
score.ScoreInfo.Mods = readScore.Mods.Select(m => m.ToMod(currentRuleset)).ToArray();
score.ScoreInfo.ClientVersion = readScore.ClientVersion;
if (readScore.TotalScoreWithoutMods is long totalScoreWithoutMods)
score.ScoreInfo.TotalScoreWithoutMods = totalScoreWithoutMods;
else
PopulateTotalScoreWithoutMods(score.ScoreInfo);
});
}
}
@ -237,6 +242,16 @@ public static void PopulateMaximumStatistics(ScoreInfo score, WorkingBeatmap wor
#pragma warning restore CS0618
}
public static void PopulateTotalScoreWithoutMods(ScoreInfo score)
{
double modMultiplier = 1;
foreach (var mod in score.Mods)
modMultiplier *= mod.ScoreMultiplier;
score.TotalScoreWithoutMods = (long)Math.Round(score.TotalScore / modMultiplier);
}
private void readLegacyReplay(Replay replay, StreamReader reader)
{
float lastTime = beatmapOffset;