Skip to content

Commit

Permalink
Split helper method for populations from replay
Browse files Browse the repository at this point in the history
  • Loading branch information
bdach committed Jul 10, 2023
1 parent e12255b commit 9e4ffc8
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 70 deletions.
103 changes: 33 additions & 70 deletions osu.Game/Database/RealmAccess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Input.Bindings;
using osu.Game.IO.Legacy;
using osu.Game.Models;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
Expand Down Expand Up @@ -914,31 +913,13 @@ void convertOnlineIDs<T>() where T : RealmObject

foreach (var score in scores)
{
string? replayFilename = score.Files.FirstOrDefault(f => f.Filename.EndsWith(@".osr", StringComparison.InvariantCultureIgnoreCase))?.File.GetStoragePath();
if (replayFilename == null)
continue;

try
score.PopulateFromReplay(files, sr =>
{
using (var stream = files.Store.GetStream(replayFilename))
{
if (stream == null)
continue;

// Trimmed down logic from LegacyScoreDecoder to extract the version from replays.
using (SerializationReader sr = new SerializationReader(stream))
{
sr.ReadByte(); // Ruleset.
int version = sr.ReadInt32();
if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
score.IsLegacyScore = true;
}
}
}
catch (Exception e)
{
Logger.Error(e, $"Failed to read replay {replayFilename} during score migration", LoggingTarget.Database);
}
sr.ReadByte(); // Ruleset.
int version = sr.ReadInt32();
if (version < LegacyScoreEncoder.FIRST_LAZER_VERSION)
score.IsLegacyScore = true;
});
}

break;
Expand Down Expand Up @@ -999,52 +980,34 @@ void convertOnlineIDs<T>() where T : RealmObject
if (!score.IsLegacyScore || !score.Ruleset.IsLegacyRuleset())
continue;

string? replayFilename = score.Files.FirstOrDefault(f => f.Filename.EndsWith(@".osr", StringComparison.InvariantCultureIgnoreCase))?.File.GetStoragePath();
if (replayFilename == null)
continue;

try
score.PopulateFromReplay(files, sr =>
{
using (var stream = files.Store.GetStream(replayFilename))
{
if (stream == null)
continue;

// Trimmed down logic from LegacyScoreDecoder to extract the mods bitmask.
using (SerializationReader sr = new SerializationReader(stream))
{
sr.ReadByte(); // Ruleset.
sr.ReadInt32(); // Version.
sr.ReadString(); // Beatmap hash.
sr.ReadString(); // Username.
sr.ReadString(); // MD5Hash.
sr.ReadUInt16(); // Count300.
sr.ReadUInt16(); // Count100.
sr.ReadUInt16(); // Count50.
sr.ReadUInt16(); // CountGeki.
sr.ReadUInt16(); // CountKatu.
sr.ReadUInt16(); // CountMiss.

// we should have this in LegacyTotalScore already, but if we're reading through this anyways...
int totalScore = sr.ReadInt32();

sr.ReadUInt16(); // Max combo.
sr.ReadBoolean(); // Perfect.

var legacyMods = (LegacyMods)sr.ReadInt32();

if (!legacyMods.HasFlagFast(LegacyMods.ScoreV2) || score.APIMods.Any(mod => mod.Acronym == @"SV2"))
continue;

score.APIMods = score.APIMods.Append(new APIMod(new ModScoreV2())).ToArray();
score.LegacyTotalScore = score.TotalScore = totalScore;
}
}
}
catch (Exception e)
{
Logger.Error(e, $"Failed to read replay {replayFilename} during score migration", LoggingTarget.Database);
}
sr.ReadByte(); // Ruleset.
sr.ReadInt32(); // Version.
sr.ReadString(); // Beatmap hash.
sr.ReadString(); // Username.
sr.ReadString(); // MD5Hash.
sr.ReadUInt16(); // Count300.
sr.ReadUInt16(); // Count100.
sr.ReadUInt16(); // Count50.
sr.ReadUInt16(); // CountGeki.
sr.ReadUInt16(); // CountKatu.
sr.ReadUInt16(); // CountMiss.
// we should have this in LegacyTotalScore already, but if we're reading through this anyways...
int totalScore = sr.ReadInt32();
sr.ReadUInt16(); // Max combo.
sr.ReadBoolean(); // Perfect.
var legacyMods = (LegacyMods)sr.ReadInt32();
if (!legacyMods.HasFlagFast(LegacyMods.ScoreV2) || score.APIMods.Any(mod => mod.Acronym == @"SV2"))
return;
score.APIMods = score.APIMods.Append(new APIMod(new ModScoreV2())).ToArray();
score.LegacyTotalScore = score.TotalScore = totalScore;
});
}

break;
Expand Down
35 changes: 35 additions & 0 deletions osu.Game/Database/StandardisedScoreMigrationTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.IO.Legacy;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Difficulty;
using osu.Game.Rulesets.Judgements;
Expand Down Expand Up @@ -287,6 +290,38 @@ public static long ConvertFromLegacyTotalScore(ScoreInfo score, DifficultyAttrib
}
}

/// <summary>
/// Used to populate the <paramref name="score"/> model using data parsed from its corresponding replay file.
/// </summary>
/// <param name="score">The score to run population from replay for.</param>
/// <param name="files">A <see cref="RealmFileStore"/> instance to use for fetching replay.</param>
/// <param name="populationFunc">
/// Delegate describing the population to execute.
/// The delegate's argument is a <see cref="SerializationReader"/> instance which permits to read data from the replay stream.
/// </param>
public static void PopulateFromReplay(this ScoreInfo score, RealmFileStore files, Action<SerializationReader> populationFunc)
{
string? replayFilename = score.Files.FirstOrDefault(f => f.Filename.EndsWith(@".osr", StringComparison.InvariantCultureIgnoreCase))?.File.GetStoragePath();
if (replayFilename == null)
return;

try
{
using (var stream = files.Store.GetStream(replayFilename))
{
if (stream == null)
return;

using (SerializationReader sr = new SerializationReader(stream))
populationFunc.Invoke(sr);
}
}
catch (Exception e)
{
Logger.Error(e, $"Failed to read replay {replayFilename} during score migration", LoggingTarget.Database);
}
}

private class FakeHit : HitObject
{
private readonly Judgement judgement;
Expand Down

0 comments on commit 9e4ffc8

Please sign in to comment.