mirror of
https://github.com/ppy/osu.git
synced 2025-01-07 23:23:12 +08:00
Move maximum statistics population to LegacyScoreDecoder
This commit is contained in:
parent
3f31593a19
commit
aa8eee0796
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -19,6 +20,7 @@ using osu.Game.Replays.Legacy;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Replays;
|
using osu.Game.Rulesets.Replays;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
using SharpCompress.Compressors.LZMA;
|
using SharpCompress.Compressors.LZMA;
|
||||||
|
|
||||||
namespace osu.Game.Scoring.Legacy
|
namespace osu.Game.Scoring.Legacy
|
||||||
@ -130,6 +132,8 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PopulateMaximumStatistics(score.ScoreInfo, workingBeatmap);
|
||||||
|
|
||||||
if (score.ScoreInfo.IsLegacyScore || compressedScoreInfo == null)
|
if (score.ScoreInfo.IsLegacyScore || compressedScoreInfo == null)
|
||||||
PopulateLegacyAccuracyAndRank(score.ScoreInfo);
|
PopulateLegacyAccuracyAndRank(score.ScoreInfo);
|
||||||
else
|
else
|
||||||
@ -170,6 +174,70 @@ namespace osu.Game.Scoring.Legacy
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="score">The score to populate the statistics of.</param>
|
||||||
|
/// <param name="workingBeatmap">The corresponding <see cref="WorkingBeatmap"/>.</param>
|
||||||
|
internal static void PopulateMaximumStatistics(ScoreInfo score, WorkingBeatmap workingBeatmap)
|
||||||
|
{
|
||||||
|
Debug.Assert(score.BeatmapInfo != null);
|
||||||
|
|
||||||
|
if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var ruleset = score.Ruleset.Detach();
|
||||||
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
var scoreProcessor = rulesetInstance.CreateScoreProcessor();
|
||||||
|
|
||||||
|
Debug.Assert(rulesetInstance != null);
|
||||||
|
|
||||||
|
// Populate the maximum statistics.
|
||||||
|
HitResult maxBasicResult = rulesetInstance.GetHitResults()
|
||||||
|
.Select(h => h.result)
|
||||||
|
.Where(h => h.IsBasic()).MaxBy(scoreProcessor.GetBaseScoreForResult);
|
||||||
|
|
||||||
|
foreach ((HitResult result, int count) in score.Statistics)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case HitResult.LargeTickHit:
|
||||||
|
case HitResult.LargeTickMiss:
|
||||||
|
score.MaximumStatistics[HitResult.LargeTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.LargeTickHit) + count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HitResult.SmallTickHit:
|
||||||
|
case HitResult.SmallTickMiss:
|
||||||
|
score.MaximumStatistics[HitResult.SmallTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit) + count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HitResult.IgnoreHit:
|
||||||
|
case HitResult.IgnoreMiss:
|
||||||
|
case HitResult.SmallBonus:
|
||||||
|
case HitResult.LargeBonus:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
score.MaximumStatistics[maxBasicResult] = score.MaximumStatistics.GetValueOrDefault(maxBasicResult) + count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!score.IsLegacyScore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
// In osu! and osu!mania, some judgements affect combo but aren't stored to scores.
|
||||||
|
// A special hit result is used to pad out the combo value to match, based on the max combo from the difficulty attributes.
|
||||||
|
var calculator = rulesetInstance.CreateDifficultyCalculator(workingBeatmap);
|
||||||
|
var attributes = calculator.Calculate(score.Mods);
|
||||||
|
|
||||||
|
int maxComboFromStatistics = score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Select(kvp => kvp.Value).DefaultIfEmpty(0).Sum();
|
||||||
|
if (attributes.MaxCombo > maxComboFromStatistics)
|
||||||
|
score.MaximumStatistics[HitResult.LegacyComboIncrease] = attributes.MaxCombo - maxComboFromStatistics;
|
||||||
|
#pragma warning restore CS0618
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Populates the accuracy of a given <see cref="ScoreInfo"/> from its contained statistics.
|
/// Populates the accuracy of a given <see cref="ScoreInfo"/> from its contained statistics.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -17,7 +17,6 @@ using osu.Game.Scoring.Legacy;
|
|||||||
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.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using Realms;
|
using Realms;
|
||||||
|
|
||||||
namespace osu.Game.Scoring
|
namespace osu.Game.Scoring
|
||||||
@ -91,8 +90,6 @@ namespace osu.Game.Scoring
|
|||||||
ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
|
ArgumentNullException.ThrowIfNull(model.BeatmapInfo);
|
||||||
ArgumentNullException.ThrowIfNull(model.Ruleset);
|
ArgumentNullException.ThrowIfNull(model.Ruleset);
|
||||||
|
|
||||||
PopulateMaximumStatistics(model);
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(model.StatisticsJson))
|
if (string.IsNullOrEmpty(model.StatisticsJson))
|
||||||
model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics);
|
model.StatisticsJson = JsonConvert.SerializeObject(model.Statistics);
|
||||||
|
|
||||||
@ -110,70 +107,6 @@ namespace osu.Game.Scoring
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="score">The score to populate the statistics of.</param>
|
|
||||||
public void PopulateMaximumStatistics(ScoreInfo score)
|
|
||||||
{
|
|
||||||
Debug.Assert(score.BeatmapInfo != null);
|
|
||||||
|
|
||||||
if (score.MaximumStatistics.Select(kvp => kvp.Value).Sum() > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var beatmap = score.BeatmapInfo!.Detach();
|
|
||||||
var ruleset = score.Ruleset.Detach();
|
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
|
||||||
var scoreProcessor = rulesetInstance.CreateScoreProcessor();
|
|
||||||
|
|
||||||
Debug.Assert(rulesetInstance != null);
|
|
||||||
|
|
||||||
// Populate the maximum statistics.
|
|
||||||
HitResult maxBasicResult = rulesetInstance.GetHitResults()
|
|
||||||
.Select(h => h.result)
|
|
||||||
.Where(h => h.IsBasic()).MaxBy(scoreProcessor.GetBaseScoreForResult);
|
|
||||||
|
|
||||||
foreach ((HitResult result, int count) in score.Statistics)
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case HitResult.LargeTickHit:
|
|
||||||
case HitResult.LargeTickMiss:
|
|
||||||
score.MaximumStatistics[HitResult.LargeTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.LargeTickHit) + count;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HitResult.SmallTickHit:
|
|
||||||
case HitResult.SmallTickMiss:
|
|
||||||
score.MaximumStatistics[HitResult.SmallTickHit] = score.MaximumStatistics.GetValueOrDefault(HitResult.SmallTickHit) + count;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HitResult.IgnoreHit:
|
|
||||||
case HitResult.IgnoreMiss:
|
|
||||||
case HitResult.SmallBonus:
|
|
||||||
case HitResult.LargeBonus:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
score.MaximumStatistics[maxBasicResult] = score.MaximumStatistics.GetValueOrDefault(maxBasicResult) + count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!score.IsLegacyScore)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#pragma warning disable CS0618
|
|
||||||
// In osu! and osu!mania, some judgements affect combo but aren't stored to scores.
|
|
||||||
// A special hit result is used to pad out the combo value to match, based on the max combo from the difficulty attributes.
|
|
||||||
var calculator = rulesetInstance.CreateDifficultyCalculator(beatmaps().GetWorkingBeatmap(beatmap));
|
|
||||||
var attributes = calculator.Calculate(score.Mods);
|
|
||||||
|
|
||||||
int maxComboFromStatistics = score.MaximumStatistics.Where(kvp => kvp.Key.AffectsCombo()).Select(kvp => kvp.Value).DefaultIfEmpty(0).Sum();
|
|
||||||
if (attributes.MaxCombo > maxComboFromStatistics)
|
|
||||||
score.MaximumStatistics[HitResult.LegacyComboIncrease] = attributes.MaxCombo - maxComboFromStatistics;
|
|
||||||
#pragma warning restore CS0618
|
|
||||||
}
|
|
||||||
|
|
||||||
// Very naive local caching to improve performance of large score imports (where the username is usually the same for most or all scores).
|
// Very naive local caching to improve performance of large score imports (where the username is usually the same for most or all scores).
|
||||||
private readonly Dictionary<string, APIUser> usernameLookupCache = new Dictionary<string, APIUser>();
|
private readonly Dictionary<string, APIUser> usernameLookupCache = new Dictionary<string, APIUser>();
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -26,6 +27,7 @@ namespace osu.Game.Scoring
|
|||||||
{
|
{
|
||||||
public class ScoreManager : ModelManager<ScoreInfo>, IModelImporter<ScoreInfo>
|
public class ScoreManager : ModelManager<ScoreInfo>, IModelImporter<ScoreInfo>
|
||||||
{
|
{
|
||||||
|
private readonly Func<BeatmapManager> beatmaps;
|
||||||
private readonly OsuConfigManager configManager;
|
private readonly OsuConfigManager configManager;
|
||||||
private readonly ScoreImporter scoreImporter;
|
private readonly ScoreImporter scoreImporter;
|
||||||
private readonly LegacyScoreExporter scoreExporter;
|
private readonly LegacyScoreExporter scoreExporter;
|
||||||
@ -44,6 +46,7 @@ namespace osu.Game.Scoring
|
|||||||
OsuConfigManager configManager = null)
|
OsuConfigManager configManager = null)
|
||||||
: base(storage, realm)
|
: base(storage, realm)
|
||||||
{
|
{
|
||||||
|
this.beatmaps = beatmaps;
|
||||||
this.configManager = configManager;
|
this.configManager = configManager;
|
||||||
|
|
||||||
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api)
|
scoreImporter = new ScoreImporter(rulesets, beatmaps, storage, realm, api)
|
||||||
@ -171,7 +174,11 @@ namespace osu.Game.Scoring
|
|||||||
/// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>.
|
/// Populates the <see cref="ScoreInfo.MaximumStatistics"/> for a given <see cref="ScoreInfo"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">The score to populate the statistics of.</param>
|
/// <param name="score">The score to populate the statistics of.</param>
|
||||||
public void PopulateMaximumStatistics(ScoreInfo score) => scoreImporter.PopulateMaximumStatistics(score);
|
public void PopulateMaximumStatistics(ScoreInfo score)
|
||||||
|
{
|
||||||
|
Debug.Assert(score.BeatmapInfo != null);
|
||||||
|
LegacyScoreDecoder.PopulateMaximumStatistics(score, beatmaps().GetWorkingBeatmap(score.BeatmapInfo.Detach()));
|
||||||
|
}
|
||||||
|
|
||||||
#region Implementation of IPresentImports<ScoreInfo>
|
#region Implementation of IPresentImports<ScoreInfo>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user