mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 21:52:55 +08:00
Update many score-related classes to move closer to being able to persist to realm
This commit is contained in:
parent
e44751c275
commit
2a4bee61dd
@ -24,7 +24,7 @@ namespace osu.Game.Database
|
||||
if (file == null)
|
||||
return;
|
||||
|
||||
using (var inputStream = UserFileStorage.GetStream(file.FileInfo.GetStoragePath()))
|
||||
using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath()))
|
||||
inputStream.CopyTo(outputStream);
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +105,6 @@ namespace osu.Game.Online.API.Requests.Responses
|
||||
OnlineID = OnlineID,
|
||||
Date = Date,
|
||||
PP = PP,
|
||||
RulesetID = RulesetID,
|
||||
Hash = HasReplay ? "online" : string.Empty, // todo: temporary?
|
||||
Rank = Rank,
|
||||
Ruleset = ruleset,
|
||||
|
@ -73,9 +73,7 @@ namespace osu.Game.Online.Rooms
|
||||
TotalScore = TotalScore,
|
||||
MaxCombo = MaxCombo,
|
||||
BeatmapInfo = beatmap,
|
||||
BeatmapInfoID = playlistItem.BeatmapID,
|
||||
Ruleset = rulesets.GetRuleset(playlistItem.RulesetID),
|
||||
RulesetID = playlistItem.RulesetID,
|
||||
Statistics = Statistics,
|
||||
User = User,
|
||||
Accuracy = Accuracy,
|
||||
|
@ -10,6 +10,7 @@ using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Users;
|
||||
using APIUser = osu.Game.Online.API.Requests.Responses.APIUser;
|
||||
|
||||
namespace osu.Game.Online.Solo
|
||||
@ -48,7 +49,7 @@ namespace osu.Game.Online.Solo
|
||||
public APIMod[] Mods { get; set; }
|
||||
|
||||
[JsonProperty("user")]
|
||||
public APIUser User { get; set; }
|
||||
public IUser User { get; set; }
|
||||
|
||||
[JsonProperty("statistics")]
|
||||
public Dictionary<HitResult, int> Statistics { get; set; }
|
||||
|
@ -481,7 +481,7 @@ namespace osu.Game
|
||||
/// Present a score's replay immediately.
|
||||
/// The user should have already requested this interactively.
|
||||
/// </summary>
|
||||
public void PresentScore(ScoreInfo score, ScorePresentType presentType = ScorePresentType.Results)
|
||||
public void PresentScore(IScoreInfo score, ScorePresentType presentType = ScorePresentType.Results)
|
||||
{
|
||||
// The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database
|
||||
// to ensure all the required data for presenting a replay are present.
|
||||
|
@ -23,6 +23,8 @@ namespace osu.Game.Scoring
|
||||
{
|
||||
public int ID { get; set; }
|
||||
|
||||
public bool IsManaged => ID > 0;
|
||||
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
public long TotalScore { get; set; }
|
||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Scoring
|
||||
{
|
||||
ScoreInfo = score;
|
||||
|
||||
string replayFilename = score.Files.FirstOrDefault(f => f.Filename.EndsWith(".osr", StringComparison.InvariantCultureIgnoreCase))?.FileInfo.GetStoragePath();
|
||||
string replayFilename = score.Files.FirstOrDefault(f => f.Filename.EndsWith(".osr", StringComparison.InvariantCultureIgnoreCase))?.File.GetStoragePath();
|
||||
|
||||
if (replayFilename == null)
|
||||
return;
|
||||
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
@ -15,6 +16,7 @@ using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Utils;
|
||||
using Realms;
|
||||
|
||||
#nullable enable
|
||||
@ -39,7 +41,18 @@ namespace osu.Game.Scoring
|
||||
[Indexed]
|
||||
public long OnlineID { get; set; } = -1;
|
||||
|
||||
public RealmUser User { get; set; } = null!;
|
||||
[MapTo("User")]
|
||||
public RealmUser RealmUser { get; set; } = null!;
|
||||
|
||||
public IUser User
|
||||
{
|
||||
get => RealmUser;
|
||||
set => RealmUser = new RealmUser
|
||||
{
|
||||
OnlineID = value.OnlineID,
|
||||
Username = value.Username
|
||||
};
|
||||
}
|
||||
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
@ -55,11 +68,20 @@ namespace osu.Game.Scoring
|
||||
|
||||
public RealmBeatmap Beatmap { get; set; } = null!;
|
||||
|
||||
public BeatmapInfo BeatmapInfo
|
||||
{
|
||||
get => new BeatmapInfo();
|
||||
// .. todo
|
||||
set => Beatmap = new RealmBeatmap(new RealmRuleset("osu", "osu!", "wangs", 0), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
|
||||
}
|
||||
|
||||
public RealmRuleset Ruleset { get; set; } = null!;
|
||||
|
||||
[Ignored]
|
||||
public Dictionary<HitResult, int> Statistics
|
||||
{
|
||||
// TODO: this is dangerous. a get operation may then modify the dictionary, which would be a fresh copy that is not persisted with the model.
|
||||
// this is already the case in multiple locations.
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(StatisticsJson))
|
||||
@ -93,6 +115,12 @@ namespace osu.Game.Scoring
|
||||
|
||||
private Mod[]? mods;
|
||||
|
||||
public int BeatmapInfoID => BeatmapInfo.ID;
|
||||
|
||||
public int UserID => RealmUser.OnlineID;
|
||||
|
||||
public int RulesetID => Ruleset.OnlineID;
|
||||
|
||||
[Ignored]
|
||||
public List<HitEvent> HitEvents { get; set; } = new List<HitEvent>();
|
||||
|
||||
@ -108,12 +136,18 @@ namespace osu.Game.Scoring
|
||||
[Ignored]
|
||||
public bool Passed { get; set; } = true;
|
||||
|
||||
[Ignored]
|
||||
public int Combo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The position of this score, starting at 1.
|
||||
/// </summary>
|
||||
[Ignored]
|
||||
public int? Position { get; set; } // TODO: remove after all calls to `CreateScoreInfo` are gone.
|
||||
|
||||
[Ignored]
|
||||
public LocalisableString DisplayAccuracy => Accuracy.FormatAccuracy();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this <see cref="EFScoreInfo"/> represents a legacy (osu!stable) score.
|
||||
/// </summary>
|
||||
|
@ -63,7 +63,7 @@ namespace osu.Game.Scoring
|
||||
// Compute difficulties asynchronously first to prevent blocking via the GetTotalScore() call below.
|
||||
foreach (var s in scores)
|
||||
{
|
||||
await difficultyCache.GetDifficultyAsync(s.BeatmapInfo, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false);
|
||||
await difficultyCache.GetDifficultyAsync(s.Beatmap, s.Ruleset, s.Mods, cancellationToken).ConfigureAwait(false);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
@ -125,7 +125,7 @@ namespace osu.Game.Scoring
|
||||
/// <returns>The total score.</returns>
|
||||
public async Task<long> GetTotalScoreAsync([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (score.BeatmapInfo == null)
|
||||
if (score.Beatmap == null)
|
||||
return score.TotalScore;
|
||||
|
||||
int beatmapMaxCombo;
|
||||
@ -146,11 +146,11 @@ namespace osu.Game.Scoring
|
||||
|
||||
// This score is guaranteed to be an osu!stable score.
|
||||
// The combo must be determined through either the beatmap's max combo value or the difficulty calculator, as lazer's scoring has changed and the score statistics cannot be used.
|
||||
if (score.BeatmapInfo.MaxCombo != null)
|
||||
beatmapMaxCombo = score.BeatmapInfo.MaxCombo.Value;
|
||||
if (score.Beatmap.MaxCombo != null)
|
||||
beatmapMaxCombo = score.Beatmap.MaxCombo.Value;
|
||||
else
|
||||
{
|
||||
if (score.BeatmapInfo.ID == 0 || difficulties == null)
|
||||
if (score.Beatmap.ID == 0 || difficulties == null)
|
||||
{
|
||||
// We don't have enough information (max combo) to compute the score, so use the provided score.
|
||||
return score.TotalScore;
|
||||
|
@ -4,10 +4,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Beatmaps;
|
||||
@ -15,10 +13,14 @@ using osu.Game.Database;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Stores;
|
||||
using Realms;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
public class ScoreModelManager : ArchiveModelManager<ScoreInfo, ScoreFileInfo>
|
||||
public class ScoreModelManager : RealmArchiveModelManager<ScoreInfo>
|
||||
{
|
||||
public override IEnumerable<string> HandledExtensions => new[] { ".osr" };
|
||||
|
||||
@ -27,18 +29,15 @@ namespace osu.Game.Scoring
|
||||
private readonly RulesetStore rulesets;
|
||||
private readonly Func<BeatmapManager> beatmaps;
|
||||
|
||||
public ScoreModelManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, IDatabaseContextFactory contextFactory, IIpcHost importHost = null)
|
||||
: base(storage, contextFactory, new ScoreStore(contextFactory, storage), importHost)
|
||||
public ScoreModelManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, RealmContextFactory contextFactory)
|
||||
: base(storage, contextFactory)
|
||||
{
|
||||
this.rulesets = rulesets;
|
||||
this.beatmaps = beatmaps;
|
||||
}
|
||||
|
||||
protected override ScoreInfo CreateModel(ArchiveReader archive)
|
||||
protected override ScoreInfo? CreateModel(ArchiveReader archive)
|
||||
{
|
||||
if (archive == null)
|
||||
return null;
|
||||
|
||||
using (var stream = archive.GetStream(archive.Filenames.First(f => f.EndsWith(".osr", StringComparison.OrdinalIgnoreCase))))
|
||||
{
|
||||
try
|
||||
@ -55,17 +54,7 @@ namespace osu.Game.Scoring
|
||||
|
||||
public Score GetScore(ScoreInfo score) => new LegacyDatabasedScore(score, rulesets, beatmaps(), Files.Store);
|
||||
|
||||
public List<ScoreInfo> GetAllUsableScores() => ModelStore.ConsumableItems.Where(s => !s.DeletePending).ToList();
|
||||
|
||||
public IEnumerable<ScoreInfo> QueryScores(Expression<Func<ScoreInfo, bool>> query) => ModelStore.ConsumableItems.AsNoTracking().Where(query);
|
||||
|
||||
public ScoreInfo Query(Expression<Func<ScoreInfo, bool>> query) => ModelStore.ConsumableItems.AsNoTracking().FirstOrDefault(query);
|
||||
|
||||
protected override Task Populate(ScoreInfo model, ArchiveReader archive, CancellationToken cancellationToken = default)
|
||||
protected override Task Populate(ScoreInfo model, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items)
|
||||
=> base.CheckLocalAvailability(model, items)
|
||||
|| (model.OnlineID > 0 && items.Any(i => i.OnlineID == model.OnlineID));
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Game.Scoring
|
||||
{
|
||||
public class ScoreStore : MutableDatabaseBackedStoreWithFileIncludes<ScoreInfo, ScoreFileInfo>
|
||||
{
|
||||
public ScoreStore(IDatabaseContextFactory factory, Storage storage)
|
||||
: base(factory, storage)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IQueryable<ScoreInfo> AddIncludesForConsumption(IQueryable<ScoreInfo> query)
|
||||
=> base.AddIncludesForConsumption(query)
|
||||
.Include(s => s.BeatmapInfo)
|
||||
.Include(s => s.BeatmapInfo).ThenInclude(b => b.Metadata)
|
||||
.Include(s => s.BeatmapInfo).ThenInclude(b => b.BeatmapSet).ThenInclude(s => s.Metadata)
|
||||
.Include(s => s.Ruleset);
|
||||
}
|
||||
}
|
@ -196,7 +196,7 @@ namespace osu.Game.Screens.Ranking
|
||||
}
|
||||
|
||||
// Find the panel corresponding to the new score.
|
||||
var expandedTrackingComponent = flow.SingleOrDefault(t => t.Panel.Score == score.NewValue);
|
||||
var expandedTrackingComponent = flow.SingleOrDefault(t => t.Panel.Score.Equals(score.NewValue));
|
||||
expandedPanel = expandedTrackingComponent?.Panel;
|
||||
|
||||
if (expandedPanel == null)
|
||||
|
@ -127,7 +127,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
if (Scope == BeatmapLeaderboardScope.Local)
|
||||
{
|
||||
var scores = scoreManager
|
||||
.QueryScores(s => !s.DeletePending && s.BeatmapInfo.ID == fetchBeatmapInfo.ID && s.Ruleset.ID == ruleset.Value.ID);
|
||||
.QueryScores(s => !s.DeletePending && s.BeatmapInfo.ID == fetchBeatmapInfo.ID && s.Ruleset.OnlineID == ruleset.Value.ID);
|
||||
|
||||
if (filterMods && !mods.Value.Any())
|
||||
{
|
||||
|
@ -12,7 +12,6 @@ using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.IO.Archives;
|
||||
using osu.Game.Models;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using Realms;
|
||||
|
Loading…
Reference in New Issue
Block a user