mirror of
https://github.com/ppy/osu.git
synced 2024-09-21 22:07:25 +08:00
Merge pull request #24794 from bdach/score-encoding-cleanup
Correctly handle multiple online score ID types
This commit is contained in:
commit
5a9d4170e8
@ -87,6 +87,34 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDecodeLegacyOnlineID()
|
||||||
|
{
|
||||||
|
var decoder = new TestLegacyScoreDecoder();
|
||||||
|
|
||||||
|
using (var resourceStream = TestResources.OpenResource("Replays/taiko-replay-with-legacy-online-id.osr"))
|
||||||
|
{
|
||||||
|
var score = decoder.Parse(resourceStream);
|
||||||
|
|
||||||
|
Assert.That(score.ScoreInfo.OnlineID, Is.EqualTo(-1));
|
||||||
|
Assert.That(score.ScoreInfo.LegacyOnlineID, Is.EqualTo(255));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDecodeNewOnlineID()
|
||||||
|
{
|
||||||
|
var decoder = new TestLegacyScoreDecoder();
|
||||||
|
|
||||||
|
using (var resourceStream = TestResources.OpenResource("Replays/taiko-replay-with-new-online-id.osr"))
|
||||||
|
{
|
||||||
|
var score = decoder.Parse(resourceStream);
|
||||||
|
|
||||||
|
Assert.That(score.ScoreInfo.OnlineID, Is.EqualTo(258));
|
||||||
|
Assert.That(score.ScoreInfo.LegacyOnlineID, Is.EqualTo(-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(3, true)]
|
[TestCase(3, true)]
|
||||||
[TestCase(6, false)]
|
[TestCase(6, false)]
|
||||||
[TestCase(LegacyBeatmapDecoder.LATEST_VERSION, false)]
|
[TestCase(LegacyBeatmapDecoder.LATEST_VERSION, false)]
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -213,7 +213,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
OnlineID = hasOnlineId ? online_score_id : 0,
|
OnlineID = hasOnlineId ? online_score_id : 0,
|
||||||
Ruleset = new OsuRuleset().RulesetInfo,
|
Ruleset = new OsuRuleset().RulesetInfo,
|
||||||
BeatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(),
|
BeatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(),
|
||||||
Hash = replayAvailable ? "online" : string.Empty,
|
HasOnlineReplay = replayAvailable,
|
||||||
User = new APIUser
|
User = new APIUser
|
||||||
{
|
{
|
||||||
Id = 39828,
|
Id = 39828,
|
||||||
|
@ -362,7 +362,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
|||||||
{
|
{
|
||||||
var score = TestResources.CreateTestScoreInfo();
|
var score = TestResources.CreateTestScoreInfo();
|
||||||
score.TotalScore += 10 - i;
|
score.TotalScore += 10 - i;
|
||||||
score.Hash = $"test{i}";
|
score.HasOnlineReplay = true;
|
||||||
scores.Add(score);
|
scores.Add(score);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,13 +10,15 @@ namespace osu.Game.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A model that contains a list of files it is responsible for.
|
/// A model that contains a list of files it is responsible for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IHasRealmFiles
|
public interface IHasRealmFiles : IHasNamedFiles
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Available files in this model, with locally filenames.
|
/// Available files in this model, with locally filenames.
|
||||||
/// When performing lookups, consider using <see cref="BeatmapSetInfoExtensions.GetFile"/> or <see cref="BeatmapSetInfoExtensions.GetPathForFile"/> to do case-insensitive lookups.
|
/// When performing lookups, consider using <see cref="BeatmapSetInfoExtensions.GetFile"/> or <see cref="BeatmapSetInfoExtensions.GetPathForFile"/> to do case-insensitive lookups.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IList<RealmNamedFileUsage> Files { get; }
|
new IList<RealmNamedFileUsage> Files { get; }
|
||||||
|
|
||||||
|
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A combined hash representing the model, based on the files it contains.
|
/// A combined hash representing the model, based on the files it contains.
|
||||||
|
@ -87,8 +87,9 @@ namespace osu.Game.Database
|
|||||||
/// 33 2023-08-16 Reset default chat toggle key binding to avoid conflict with newly added leaderboard toggle key binding.
|
/// 33 2023-08-16 Reset default chat toggle key binding to avoid conflict with newly added leaderboard toggle key binding.
|
||||||
/// 34 2023-08-21 Add BackgroundReprocessingFailed flag to ScoreInfo to track upgrade failures.
|
/// 34 2023-08-21 Add BackgroundReprocessingFailed flag to ScoreInfo to track upgrade failures.
|
||||||
/// 35 2023-10-16 Clear key combinations of keybindings that are assigned to more than one action in a given settings section.
|
/// 35 2023-10-16 Clear key combinations of keybindings that are assigned to more than one action in a given settings section.
|
||||||
|
/// 36 2023-10-26 Add LegacyOnlineID to ScoreInfo. Move osu_scores_*_high IDs stored in OnlineID to LegacyOnlineID. Reset anomalous OnlineIDs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int schema_version = 35;
|
private const int schema_version = 36;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
||||||
@ -1075,6 +1076,24 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 36:
|
||||||
|
{
|
||||||
|
foreach (var score in migration.NewRealm.All<ScoreInfo>())
|
||||||
|
{
|
||||||
|
if (score.OnlineID > 0)
|
||||||
|
{
|
||||||
|
score.LegacyOnlineID = score.OnlineID;
|
||||||
|
score.OnlineID = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
score.LegacyOnlineID = score.OnlineID = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Log($"Migration completed in {stopwatch.ElapsedMilliseconds}ms");
|
Logger.Log($"Migration completed in {stopwatch.ElapsedMilliseconds}ms");
|
||||||
|
@ -114,8 +114,24 @@ namespace osu.Game.Extensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="instance">The instance to compare.</param>
|
/// <param name="instance">The instance to compare.</param>
|
||||||
/// <param name="other">The other instance to compare against.</param>
|
/// <param name="other">The other instance to compare against.</param>
|
||||||
/// <returns>Whether online IDs match. If either instance is missing an online ID, this will return false.</returns>
|
/// <returns>
|
||||||
public static bool MatchesOnlineID(this IScoreInfo? instance, IScoreInfo? other) => matchesOnlineID(instance, other);
|
/// Whether online IDs match.
|
||||||
|
/// Both <see cref="IHasOnlineID{T}.OnlineID"/> and <see cref="IScoreInfo.LegacyOnlineID"/> are checked, in that order.
|
||||||
|
/// If either instance is missing an online ID, this will return false.
|
||||||
|
/// </returns>
|
||||||
|
public static bool MatchesOnlineID(this IScoreInfo? instance, IScoreInfo? other)
|
||||||
|
{
|
||||||
|
if (matchesOnlineID(instance, other))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (instance == null || other == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (instance.LegacyOnlineID < 0 || other.LegacyOnlineID < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return instance.LegacyOnlineID.Equals(other.LegacyOnlineID);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool matchesOnlineID(this IHasOnlineID<long>? instance, IHasOnlineID<long>? other)
|
private static bool matchesOnlineID(this IHasOnlineID<long>? instance, IHasOnlineID<long>? other)
|
||||||
{
|
{
|
||||||
|
@ -7,16 +7,16 @@ using System.Linq;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Converters;
|
using Newtonsoft.Json.Converters;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Online.API.Requests.Responses
|
namespace osu.Game.Online.API.Requests.Responses
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class SoloScoreInfo : IHasOnlineID<long>
|
public class SoloScoreInfo : IScoreInfo
|
||||||
{
|
{
|
||||||
[JsonProperty("beatmap_id")]
|
[JsonProperty("beatmap_id")]
|
||||||
public int BeatmapID { get; set; }
|
public int BeatmapID { get; set; }
|
||||||
@ -138,6 +138,18 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region IScoreInfo
|
||||||
|
|
||||||
|
public long OnlineID => (long?)ID ?? -1;
|
||||||
|
|
||||||
|
IUser IScoreInfo.User => User!;
|
||||||
|
DateTimeOffset IScoreInfo.Date => EndedAt;
|
||||||
|
long IScoreInfo.LegacyOnlineID => (long?)LegacyScoreId ?? -1;
|
||||||
|
IBeatmapInfo IScoreInfo.Beatmap => Beatmap!;
|
||||||
|
IRulesetInfo IScoreInfo.Ruleset => Beatmap!.Ruleset;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public override string ToString() => $"score_id: {ID} user_id: {UserID}";
|
public override string ToString() => $"score_id: {ID} user_id: {UserID}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -178,6 +190,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
var score = new ScoreInfo
|
var score = new ScoreInfo
|
||||||
{
|
{
|
||||||
OnlineID = OnlineID,
|
OnlineID = OnlineID,
|
||||||
|
LegacyOnlineID = (long?)LegacyScoreId ?? -1,
|
||||||
User = User ?? new APIUser { Id = UserID },
|
User = User ?? new APIUser { Id = UserID },
|
||||||
BeatmapInfo = new BeatmapInfo { OnlineID = BeatmapID },
|
BeatmapInfo = new BeatmapInfo { OnlineID = BeatmapID },
|
||||||
Ruleset = new RulesetInfo { OnlineID = RulesetID },
|
Ruleset = new RulesetInfo { OnlineID = RulesetID },
|
||||||
@ -189,7 +202,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Statistics = Statistics,
|
Statistics = Statistics,
|
||||||
MaximumStatistics = MaximumStatistics,
|
MaximumStatistics = MaximumStatistics,
|
||||||
Date = EndedAt,
|
Date = EndedAt,
|
||||||
Hash = HasReplay ? "online" : string.Empty, // TODO: temporary?
|
HasOnlineReplay = HasReplay,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
PP = PP,
|
PP = PP,
|
||||||
};
|
};
|
||||||
@ -223,7 +236,5 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
||||||
MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
||||||
};
|
};
|
||||||
|
|
||||||
public long OnlineID => (long?)ID ?? -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,9 @@ namespace osu.Game.Online.Rooms
|
|||||||
[JsonProperty("position")]
|
[JsonProperty("position")]
|
||||||
public int? Position { get; set; }
|
public int? Position { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("has_replay")]
|
||||||
|
public bool HasReplay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Any scores in the room around this score.
|
/// Any scores in the room around this score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -84,7 +87,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
User = User,
|
User = User,
|
||||||
Accuracy = Accuracy,
|
Accuracy = Accuracy,
|
||||||
Date = EndedAt,
|
Date = EndedAt,
|
||||||
Hash = string.Empty, // todo: temporary?
|
HasOnlineReplay = HasReplay,
|
||||||
Rank = Rank,
|
Rank = Rank,
|
||||||
Mods = Mods?.Select(m => m.ToMod(rulesetInstance)).ToArray() ?? Array.Empty<Mod>(),
|
Mods = Mods?.Select(m => m.ToMod(rulesetInstance)).ToArray() ?? Array.Empty<Mod>(),
|
||||||
Position = Position,
|
Position = Position,
|
||||||
|
@ -39,7 +39,8 @@ namespace osu.Game.Online
|
|||||||
var scoreInfo = new ScoreInfo
|
var scoreInfo = new ScoreInfo
|
||||||
{
|
{
|
||||||
ID = TrackedItem.ID,
|
ID = TrackedItem.ID,
|
||||||
OnlineID = TrackedItem.OnlineID
|
OnlineID = TrackedItem.OnlineID,
|
||||||
|
LegacyOnlineID = TrackedItem.LegacyOnlineID
|
||||||
};
|
};
|
||||||
|
|
||||||
Downloader.DownloadBegan += downloadBegan;
|
Downloader.DownloadBegan += downloadBegan;
|
||||||
@ -47,6 +48,7 @@ namespace osu.Game.Online
|
|||||||
|
|
||||||
realmSubscription = realm.RegisterForNotifications(r => r.All<ScoreInfo>().Where(s =>
|
realmSubscription = realm.RegisterForNotifications(r => r.All<ScoreInfo>().Where(s =>
|
||||||
((s.OnlineID > 0 && s.OnlineID == TrackedItem.OnlineID)
|
((s.OnlineID > 0 && s.OnlineID == TrackedItem.OnlineID)
|
||||||
|
|| (s.LegacyOnlineID > 0 && s.LegacyOnlineID == TrackedItem.LegacyOnlineID)
|
||||||
|| (!string.IsNullOrEmpty(s.Hash) && s.Hash == TrackedItem.Hash))
|
|| (!string.IsNullOrEmpty(s.Hash) && s.Hash == TrackedItem.Hash))
|
||||||
&& !s.DeletePending), (items, _) =>
|
&& !s.DeletePending), (items, _) =>
|
||||||
{
|
{
|
||||||
|
@ -678,6 +678,9 @@ namespace osu.Game
|
|||||||
if (score.OnlineID > 0)
|
if (score.OnlineID > 0)
|
||||||
databasedScoreInfo = ScoreManager.Query(s => s.OnlineID == score.OnlineID);
|
databasedScoreInfo = ScoreManager.Query(s => s.OnlineID == score.OnlineID);
|
||||||
|
|
||||||
|
if (score.LegacyOnlineID > 0)
|
||||||
|
databasedScoreInfo ??= ScoreManager.Query(s => s.LegacyOnlineID == score.LegacyOnlineID);
|
||||||
|
|
||||||
if (score is ScoreInfo scoreInfo)
|
if (score is ScoreInfo scoreInfo)
|
||||||
databasedScoreInfo ??= ScoreManager.Query(s => s.Hash == scoreInfo.Hash);
|
databasedScoreInfo ??= ScoreManager.Query(s => s.Hash == scoreInfo.Hash);
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ using osu.Game.Users;
|
|||||||
|
|
||||||
namespace osu.Game.Scoring
|
namespace osu.Game.Scoring
|
||||||
{
|
{
|
||||||
public interface IScoreInfo : IHasOnlineID<long>, IHasNamedFiles
|
public interface IScoreInfo : IHasOnlineID<long>
|
||||||
{
|
{
|
||||||
IUser User { get; }
|
IUser User { get; }
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
double Accuracy { get; }
|
double Accuracy { get; }
|
||||||
|
|
||||||
bool HasReplay { get; }
|
long LegacyOnlineID { get; }
|
||||||
|
|
||||||
DateTimeOffset Date { get; }
|
DateTimeOffset Date { get; }
|
||||||
|
|
||||||
|
@ -19,6 +19,13 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
[JsonObject(MemberSerialization.OptIn)]
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
public class LegacyReplaySoloScoreInfo
|
public class LegacyReplaySoloScoreInfo
|
||||||
{
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// The value of this property should correspond to <see cref="ScoreInfo.OnlineID"/>
|
||||||
|
/// (i.e. come from the `solo_scores` ID scheme).
|
||||||
|
/// </remarks>
|
||||||
|
[JsonProperty("online_id")]
|
||||||
|
public long OnlineID { get; set; } = -1;
|
||||||
|
|
||||||
[JsonProperty("mods")]
|
[JsonProperty("mods")]
|
||||||
public APIMod[] Mods { get; set; } = Array.Empty<APIMod>();
|
public APIMod[] Mods { get; set; } = Array.Empty<APIMod>();
|
||||||
|
|
||||||
@ -30,6 +37,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
|
|
||||||
public static LegacyReplaySoloScoreInfo FromScore(ScoreInfo score) => new LegacyReplaySoloScoreInfo
|
public static LegacyReplaySoloScoreInfo FromScore(ScoreInfo score) => new LegacyReplaySoloScoreInfo
|
||||||
{
|
{
|
||||||
|
OnlineID = score.OnlineID,
|
||||||
Mods = score.APIMods,
|
Mods = score.APIMods,
|
||||||
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
Statistics = score.Statistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
||||||
MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
MaximumStatistics = score.MaximumStatistics.Where(kvp => kvp.Value != 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value),
|
||||||
|
@ -101,9 +101,9 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
byte[] compressedReplay = sr.ReadByteArray();
|
byte[] compressedReplay = sr.ReadByteArray();
|
||||||
|
|
||||||
if (version >= 20140721)
|
if (version >= 20140721)
|
||||||
scoreInfo.OnlineID = sr.ReadInt64();
|
scoreInfo.LegacyOnlineID = sr.ReadInt64();
|
||||||
else if (version >= 20121008)
|
else if (version >= 20121008)
|
||||||
scoreInfo.OnlineID = sr.ReadInt32();
|
scoreInfo.LegacyOnlineID = sr.ReadInt32();
|
||||||
|
|
||||||
byte[] compressedScoreInfo = null;
|
byte[] compressedScoreInfo = null;
|
||||||
|
|
||||||
@ -121,6 +121,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
|
|
||||||
Debug.Assert(readScore != null);
|
Debug.Assert(readScore != null);
|
||||||
|
|
||||||
|
score.ScoreInfo.OnlineID = readScore.OnlineID;
|
||||||
score.ScoreInfo.Statistics = readScore.Statistics;
|
score.ScoreInfo.Statistics = readScore.Statistics;
|
||||||
score.ScoreInfo.MaximumStatistics = readScore.MaximumStatistics;
|
score.ScoreInfo.MaximumStatistics = readScore.MaximumStatistics;
|
||||||
score.ScoreInfo.Mods = readScore.Mods.Select(m => m.ToMod(currentRuleset)).ToArray();
|
score.ScoreInfo.Mods = readScore.Mods.Select(m => m.ToMod(currentRuleset)).ToArray();
|
||||||
|
@ -84,7 +84,7 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
sw.Write(getHpGraphFormatted());
|
sw.Write(getHpGraphFormatted());
|
||||||
sw.Write(score.ScoreInfo.Date.DateTime);
|
sw.Write(score.ScoreInfo.Date.DateTime);
|
||||||
sw.WriteByteArray(createReplayData());
|
sw.WriteByteArray(createReplayData());
|
||||||
sw.Write((long)0);
|
sw.Write(score.ScoreInfo.LegacyOnlineID);
|
||||||
writeModSpecificData(score.ScoreInfo, sw);
|
writeModSpecificData(score.ScoreInfo, sw);
|
||||||
sw.WriteByteArray(createScoreInfoData());
|
sw.WriteByteArray(createScoreInfoData());
|
||||||
}
|
}
|
||||||
|
@ -94,15 +94,32 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
public double Accuracy { get; set; }
|
public double Accuracy { get; set; }
|
||||||
|
|
||||||
public bool HasReplay => !string.IsNullOrEmpty(Hash);
|
[Ignored]
|
||||||
|
public bool HasOnlineReplay { get; set; }
|
||||||
|
|
||||||
public DateTimeOffset Date { get; set; }
|
public DateTimeOffset Date { get; set; }
|
||||||
|
|
||||||
public double? PP { get; set; }
|
public double? PP { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The online ID of this score.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In the osu-web database, this ID (if present) comes from the new <c>solo_scores</c> table.
|
||||||
|
/// </remarks>
|
||||||
[Indexed]
|
[Indexed]
|
||||||
public long OnlineID { get; set; } = -1;
|
public long OnlineID { get; set; } = -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The legacy online ID of this score.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In the osu-web database, this ID (if present) comes from the legacy <c>osu_scores_*_high</c> tables.
|
||||||
|
/// This ID is also stored to replays set on osu!stable.
|
||||||
|
/// </remarks>
|
||||||
|
[Indexed]
|
||||||
|
public long LegacyOnlineID { get; set; } = -1;
|
||||||
|
|
||||||
[MapTo("User")]
|
[MapTo("User")]
|
||||||
public RealmUser RealmUser { get; set; } = null!;
|
public RealmUser RealmUser { get; set; } = null!;
|
||||||
|
|
||||||
@ -168,7 +185,6 @@ namespace osu.Game.Scoring
|
|||||||
IRulesetInfo IScoreInfo.Ruleset => Ruleset;
|
IRulesetInfo IScoreInfo.Ruleset => Ruleset;
|
||||||
IBeatmapInfo? IScoreInfo.Beatmap => BeatmapInfo;
|
IBeatmapInfo? IScoreInfo.Beatmap => BeatmapInfo;
|
||||||
IUser IScoreInfo.User => User;
|
IUser IScoreInfo.User => User;
|
||||||
IEnumerable<INamedFileUsage> IHasNamedFiles.Files => Files;
|
|
||||||
|
|
||||||
#region Properties required to make things work with existing usages
|
#region Properties required to make things work with existing usages
|
||||||
|
|
||||||
|
@ -150,7 +150,11 @@ namespace osu.Game.Scoring
|
|||||||
|
|
||||||
public Task Import(ImportTask[] imports, ImportParameters parameters = default) => scoreImporter.Import(imports, parameters);
|
public Task Import(ImportTask[] imports, ImportParameters parameters = default) => scoreImporter.Import(imports, parameters);
|
||||||
|
|
||||||
public override bool IsAvailableLocally(ScoreInfo model) => Realm.Run(realm => realm.All<ScoreInfo>().Any(s => s.OnlineID == model.OnlineID));
|
public override bool IsAvailableLocally(ScoreInfo model)
|
||||||
|
=> Realm.Run(realm => realm.All<ScoreInfo>()
|
||||||
|
// this basically inlines `ModelExtension.MatchesOnlineID(IScoreInfo, IScoreInfo)`,
|
||||||
|
// because that method can't be used here, as realm can't translate it to its query language.
|
||||||
|
.Any(s => s.OnlineID == model.OnlineID || s.LegacyOnlineID == model.LegacyOnlineID));
|
||||||
|
|
||||||
public IEnumerable<string> HandledExtensions => scoreImporter.HandledExtensions;
|
public IEnumerable<string> HandledExtensions => scoreImporter.HandledExtensions;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
public partial class MultiplayerResultsScreen : PlaylistsResultsScreen
|
public partial class MultiplayerResultsScreen : PlaylistsResultsScreen
|
||||||
{
|
{
|
||||||
public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem)
|
public MultiplayerResultsScreen(ScoreInfo score, long roomId, PlaylistItem playlistItem)
|
||||||
: base(score, roomId, playlistItem, false, false)
|
: base(score, roomId, playlistItem, false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1167,13 +1167,6 @@ namespace osu.Game.Screens.Play
|
|||||||
// the import process will re-attach managed beatmap/rulesets to this score. we don't want this for now, so create a temporary copy to import.
|
// the import process will re-attach managed beatmap/rulesets to this score. we don't want this for now, so create a temporary copy to import.
|
||||||
var importableScore = score.ScoreInfo.DeepClone();
|
var importableScore = score.ScoreInfo.DeepClone();
|
||||||
|
|
||||||
// For the time being, online ID responses are not really useful for anything.
|
|
||||||
// In addition, the IDs provided via new (lazer) endpoints are based on a different autoincrement from legacy (stable) scores.
|
|
||||||
//
|
|
||||||
// Until we better define the server-side logic behind this, let's not store the online ID to avoid potential unique constraint
|
|
||||||
// conflicts across various systems (ie. solo and multiplayer).
|
|
||||||
importableScore.OnlineID = -1;
|
|
||||||
|
|
||||||
var imported = scoreManager.Import(importableScore, replayReader);
|
var imported = scoreManager.Import(importableScore, replayReader);
|
||||||
|
|
||||||
imported.PerformRead(s =>
|
imported.PerformRead(s =>
|
||||||
|
@ -37,7 +37,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
if (State.Value == DownloadState.LocallyAvailable)
|
if (State.Value == DownloadState.LocallyAvailable)
|
||||||
return ReplayAvailability.Local;
|
return ReplayAvailability.Local;
|
||||||
|
|
||||||
if (Score.Value?.HasReplay == true)
|
if (Score.Value?.HasOnlineReplay == true)
|
||||||
return ReplayAvailability.Online;
|
return ReplayAvailability.Online;
|
||||||
|
|
||||||
return ReplayAvailability.NotAvailable;
|
return ReplayAvailability.NotAvailable;
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.Solo;
|
using osu.Game.Online.Solo;
|
||||||
@ -67,7 +68,7 @@ namespace osu.Game.Screens.Ranking
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
getScoreRequest = new GetScoresRequest(Score.BeatmapInfo, Score.Ruleset);
|
||||||
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => s.OnlineID != Score.OnlineID).Select(s => s.ToScoreInfo(rulesets, Beatmap.Value.BeatmapInfo)));
|
getScoreRequest.Success += r => scoresCallback?.Invoke(r.Scores.Where(s => !s.MatchesOnlineID(Score)).Select(s => s.ToScoreInfo(rulesets, Beatmap.Value.BeatmapInfo)));
|
||||||
return getScoreRequest;
|
return getScoreRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace osu.Game.Skinning
|
|||||||
{
|
{
|
||||||
[MapTo("Skin")]
|
[MapTo("Skin")]
|
||||||
[JsonObject(MemberSerialization.OptIn)]
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable<SkinInfo>, IHasGuidPrimaryKey, ISoftDelete, IHasNamedFiles
|
public class SkinInfo : RealmObject, IHasRealmFiles, IEquatable<SkinInfo>, IHasGuidPrimaryKey, ISoftDelete
|
||||||
{
|
{
|
||||||
internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD");
|
internal static readonly Guid TRIANGLES_SKIN = new Guid("2991CFD8-2140-469A-BCB9-2EC23FBCE4AD");
|
||||||
internal static readonly Guid ARGON_SKIN = new Guid("CFFA69DE-B3E3-4DEE-8563-3C4F425C05D0");
|
internal static readonly Guid ARGON_SKIN = new Guid("CFFA69DE-B3E3-4DEE-8563-3C4F425C05D0");
|
||||||
|
Loading…
Reference in New Issue
Block a user