mirror of
https://github.com/ppy/osu.git
synced 2025-01-15 06:42:56 +08:00
Refactoring
This commit is contained in:
parent
e291dff5ad
commit
09bc8e45de
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
|
||||
if (ComputeLegacyScoringValues)
|
||||
{
|
||||
CatchScoreV1Processor sv1Processor = new CatchScoreV1Processor();
|
||||
CatchLegacyScoreProcessor sv1Processor = new CatchLegacyScoreProcessor();
|
||||
sv1Processor.Simulate(workingBeatmap, beatmap, mods);
|
||||
attributes.LegacyAccuracyScore = sv1Processor.AccuracyScore;
|
||||
attributes.LegacyComboScore = sv1Processor.ComboScore;
|
||||
|
@ -14,22 +14,12 @@ using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||
{
|
||||
internal class CatchScoreV1Processor : ILegacyScoreProcessor
|
||||
internal class CatchLegacyScoreProcessor : ILegacyScoreProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// The accuracy portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int AccuracyScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The combo-multiplied portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int ComboScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
|
||||
/// This is made up of all judgements that would be <see cref="HitResult.SmallBonus"/> or <see cref="HitResult.LargeBonus"/>.
|
||||
/// </summary>
|
||||
public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
|
||||
|
||||
private int legacyBonusScore;
|
@ -62,7 +62,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
|
||||
if (ComputeLegacyScoringValues)
|
||||
{
|
||||
ManiaScoreV1Processor sv1Processor = new ManiaScoreV1Processor();
|
||||
ManiaLegacyScoreProcessor sv1Processor = new ManiaLegacyScoreProcessor();
|
||||
sv1Processor.Simulate(workingBeatmap, beatmap, mods);
|
||||
attributes.LegacyAccuracyScore = sv1Processor.AccuracyScore;
|
||||
attributes.LegacyComboScore = sv1Processor.ComboScore;
|
||||
|
@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||
{
|
||||
internal class ManiaScoreV1Processor : ILegacyScoreProcessor
|
||||
internal class ManiaLegacyScoreProcessor : ILegacyScoreProcessor
|
||||
{
|
||||
public int AccuracyScore => 0;
|
||||
public int ComboScore { get; private set; }
|
@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
|
||||
if (ComputeLegacyScoringValues)
|
||||
{
|
||||
OsuScoreV1Processor sv1Processor = new OsuScoreV1Processor();
|
||||
OsuLegacyScoreProcessor sv1Processor = new OsuLegacyScoreProcessor();
|
||||
sv1Processor.Simulate(workingBeatmap, beatmap, mods);
|
||||
attributes.LegacyAccuracyScore = sv1Processor.AccuracyScore;
|
||||
attributes.LegacyComboScore = sv1Processor.ComboScore;
|
||||
|
@ -14,22 +14,12 @@ using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||
{
|
||||
internal class OsuScoreV1Processor : ILegacyScoreProcessor
|
||||
internal class OsuLegacyScoreProcessor : ILegacyScoreProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// The accuracy portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int AccuracyScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The combo-multiplied portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int ComboScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
|
||||
/// This is made up of all judgements that would be <see cref="HitResult.SmallBonus"/> or <see cref="HitResult.LargeBonus"/>.
|
||||
/// </summary>
|
||||
public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
|
||||
|
||||
private int legacyBonusScore;
|
@ -323,6 +323,6 @@ namespace osu.Game.Rulesets.Osu
|
||||
|
||||
public override RulesetSetupSection CreateEditorSetupSection() => new OsuSetupSection();
|
||||
|
||||
public override ILegacyScoreProcessor CreateLegacyScoreProcessor() => new OsuScoreV1Processor();
|
||||
public override ILegacyScoreProcessor CreateLegacyScoreProcessor() => new OsuLegacyScoreProcessor();
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
|
||||
if (ComputeLegacyScoringValues)
|
||||
{
|
||||
TaikoScoreV1Processor sv1Processor = new TaikoScoreV1Processor();
|
||||
TaikoLegacyScoreProcessor sv1Processor = new TaikoLegacyScoreProcessor();
|
||||
sv1Processor.Simulate(workingBeatmap, beatmap, mods);
|
||||
attributes.LegacyAccuracyScore = sv1Processor.AccuracyScore;
|
||||
attributes.LegacyComboScore = sv1Processor.ComboScore;
|
||||
|
@ -14,22 +14,12 @@ using osu.Game.Rulesets.Taiko.Objects;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||
{
|
||||
internal class TaikoScoreV1Processor : ILegacyScoreProcessor
|
||||
internal class TaikoLegacyScoreProcessor : ILegacyScoreProcessor
|
||||
{
|
||||
/// <summary>
|
||||
/// The accuracy portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int AccuracyScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The combo-multiplied portion of the legacy (ScoreV1) total score.
|
||||
/// </summary>
|
||||
public int ComboScore { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// A ratio of <c>new_bonus_score / old_bonus_score</c> for converting the bonus score of legacy scores to the new scoring.
|
||||
/// This is made up of all judgements that would be <see cref="HitResult.SmallBonus"/> or <see cref="HitResult.LargeBonus"/>.
|
||||
/// </summary>
|
||||
public double BonusScoreRatio => legacyBonusScore == 0 ? 0 : (double)modernBonusScore / legacyBonusScore;
|
||||
|
||||
private int legacyBonusScore;
|
@ -18,6 +18,7 @@ using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Scoring.Legacy;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Game
|
||||
@ -27,6 +28,9 @@ namespace osu.Game
|
||||
[Resolved]
|
||||
private RulesetStore rulesetStore { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private BeatmapManager beatmapManager { get; set; } = null!;
|
||||
|
||||
[Resolved]
|
||||
private ScoreManager scoreManager { get; set; } = null!;
|
||||
|
||||
@ -241,7 +245,7 @@ namespace osu.Game
|
||||
try
|
||||
{
|
||||
var score = scoreManager.Query(s => s.ID == id);
|
||||
long newTotalScore = scoreManager.ConvertFromLegacyTotalScore(score);
|
||||
long newTotalScore = StandardisedScoreMigrationTools.ConvertFromLegacyTotalScore(score, beatmapManager);
|
||||
|
||||
// Can't use async overload because we're not on the update thread.
|
||||
// ReSharper disable once MethodHasAsyncOverload
|
||||
@ -249,7 +253,7 @@ namespace osu.Game
|
||||
{
|
||||
ScoreInfo s = r.Find<ScoreInfo>(id);
|
||||
s.TotalScore = newTotalScore;
|
||||
s.Version = 30000003;
|
||||
s.Version = LegacyScoreEncoder.LATEST_VERSION;
|
||||
});
|
||||
|
||||
Logger.Log($"Converted total score for score {id}");
|
||||
|
@ -78,7 +78,7 @@ namespace osu.Game.Database
|
||||
/// 28 2023-06-08 Added IsLegacyScore to ScoreInfo, parsed from replay files.
|
||||
/// 29 2023-06-12 Run migration of old lazer scores to be best-effort in the new scoring number space. No actual realm changes.
|
||||
/// 30 2023-06-16 Run migration of old lazer scores again. This time with more correct rounding considerations.
|
||||
/// 31 2023-06-26 Add Version and LegacyTotalScore to ScoreInfo, set Version to 30000002 and move TotalScore into LegacyTotalScore for legacy scores.
|
||||
/// 31 2023-06-26 Add Version and LegacyTotalScore to ScoreInfo, set Version to 30000002 and copy TotalScore into LegacyTotalScore for legacy scores.
|
||||
/// </summary>
|
||||
private const int schema_version = 31;
|
||||
|
||||
@ -974,8 +974,15 @@ namespace osu.Game.Database
|
||||
|
||||
foreach (var score in scores)
|
||||
{
|
||||
score.LegacyTotalScore = score.TotalScore;
|
||||
score.Version = 30000002; // Last version before legacy total score conversion.
|
||||
if (score.IsLegacyScore)
|
||||
{
|
||||
score.LegacyTotalScore = score.TotalScore;
|
||||
|
||||
// Scores with this version will trigger the update process in BackgroundBeatmapProcessor.
|
||||
score.Version = 30000002;
|
||||
}
|
||||
else
|
||||
score.Version = LegacyScoreEncoder.LATEST_VERSION;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Difficulty;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
@ -185,6 +186,92 @@ namespace osu.Game.Database
|
||||
return (long)Math.Round((1000000 * (accuracyPortion * accuracyScore + (1 - accuracyPortion) * comboScore) + bonusScore) * modMultiplier);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from <see cref="ScoreInfo.LegacyTotalScore"/> to the new standardised scoring of <see cref="ScoreProcessor"/>.
|
||||
/// </summary>
|
||||
/// <param name="score">The score to convert the total score of.</param>
|
||||
/// <param name="beatmaps">A <see cref="BeatmapManager"/> used for <see cref="WorkingBeatmap"/> lookups.</param>
|
||||
/// <returns>The standardised total score.</returns>
|
||||
public static long ConvertFromLegacyTotalScore(ScoreInfo score, BeatmapManager beatmaps)
|
||||
{
|
||||
if (!score.IsLegacyScore)
|
||||
return score.TotalScore;
|
||||
|
||||
var beatmap = beatmaps.GetWorkingBeatmap(score.BeatmapInfo);
|
||||
var ruleset = score.Ruleset.CreateInstance();
|
||||
|
||||
var sv1Processor = ruleset.CreateLegacyScoreProcessor();
|
||||
if (sv1Processor == null)
|
||||
return score.TotalScore;
|
||||
|
||||
sv1Processor.Simulate(beatmap, beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods), score.Mods);
|
||||
|
||||
return ConvertFromLegacyTotalScore(score, new DifficultyAttributes
|
||||
{
|
||||
LegacyAccuracyScore = sv1Processor.AccuracyScore,
|
||||
LegacyComboScore = sv1Processor.ComboScore,
|
||||
LegacyBonusScoreRatio = sv1Processor.BonusScoreRatio
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from <see cref="ScoreInfo.LegacyTotalScore"/> to the new standardised scoring of <see cref="ScoreProcessor"/>.
|
||||
/// </summary>
|
||||
/// <param name="score">The score to convert the total score of.</param>
|
||||
/// <param name="attributes">Difficulty attributes providing the legacy scoring values
|
||||
/// (<see cref="DifficultyAttributes.LegacyAccuracyScore"/>, <see cref="DifficultyAttributes.LegacyComboScore"/>, and <see cref="DifficultyAttributes.LegacyBonusScoreRatio"/>)
|
||||
/// for the beatmap which the score was set on.</param>
|
||||
/// <returns>The standardised total score.</returns>
|
||||
public static long ConvertFromLegacyTotalScore(ScoreInfo score, DifficultyAttributes attributes)
|
||||
{
|
||||
if (!score.IsLegacyScore)
|
||||
return score.TotalScore;
|
||||
|
||||
int maximumLegacyAccuracyScore = attributes.LegacyAccuracyScore;
|
||||
int maximumLegacyComboScore = attributes.LegacyComboScore;
|
||||
double maximumLegacyBonusRatio = attributes.LegacyBonusScoreRatio;
|
||||
double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n);
|
||||
|
||||
// The part of total score that doesn't include bonus.
|
||||
int maximumLegacyBaseScore = maximumLegacyAccuracyScore + maximumLegacyComboScore;
|
||||
|
||||
// The combo proportion is calculated as a proportion of maximumLegacyBaseScore.
|
||||
double comboProportion = Math.Min(1, (double)score.LegacyTotalScore / maximumLegacyBaseScore);
|
||||
|
||||
// The bonus proportion makes up the rest of the score that exceeds maximumLegacyBaseScore.
|
||||
double bonusProportion = Math.Max(0, (score.LegacyTotalScore - maximumLegacyBaseScore) * maximumLegacyBonusRatio);
|
||||
|
||||
switch (score.Ruleset.OnlineID)
|
||||
{
|
||||
case 0:
|
||||
return (long)Math.Round((
|
||||
700000 * comboProportion
|
||||
+ 300000 * Math.Pow(score.Accuracy, 10)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 1:
|
||||
return (long)Math.Round((
|
||||
250000 * comboProportion
|
||||
+ 750000 * Math.Pow(score.Accuracy, 3.6)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 2:
|
||||
return (long)Math.Round((
|
||||
600000 * comboProportion
|
||||
+ 400000 * score.Accuracy
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 3:
|
||||
return (long)Math.Round((
|
||||
990000 * comboProportion
|
||||
+ 10000 * Math.Pow(score.Accuracy, 2 + 2 * score.Accuracy)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
default:
|
||||
return score.TotalScore;
|
||||
}
|
||||
}
|
||||
|
||||
private class FakeHit : HitObject
|
||||
{
|
||||
private readonly Judgement judgement;
|
||||
|
@ -99,7 +99,7 @@ namespace osu.Game
|
||||
/// </summary>
|
||||
private const double global_track_volume_adjust = 0.8;
|
||||
|
||||
public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild;
|
||||
public virtual bool UseDevelopmentServer => false;
|
||||
|
||||
public virtual EndpointConfiguration CreateEndpoints() =>
|
||||
UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ExperimentalEndpointConfiguration();
|
||||
|
@ -25,6 +25,13 @@ namespace osu.Game.Rulesets.Scoring
|
||||
/// </summary>
|
||||
double BonusScoreRatio { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Performs the simulation, computing the maximum <see cref="AccuracyScore"/>, <see cref="ComboScore"/>,
|
||||
/// and <see cref="BonusScoreRatio"/> achievable for the given beatmap.
|
||||
/// </summary>
|
||||
/// <param name="workingBeatmap">The working beatmap.</param>
|
||||
/// <param name="playableBeatmap">A playable version of the beatmap for the ruleset.</param>
|
||||
/// <param name="mods">The applied mods.</param>
|
||||
void Simulate(IWorkingBeatmap workingBeatmap, IBeatmap playableBeatmap, IReadOnlyList<Mod> mods);
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Scoring.Legacy
|
||||
/// <list type="bullet">
|
||||
/// <item><description>30000001: Appends <see cref="LegacyReplaySoloScoreInfo"/> to the end of scores.</description></item>
|
||||
/// <item><description>30000002: Score stored to replay calculated using the Score V2 algorithm.</description></item>
|
||||
/// <item><description>30000003: First version after legacy total score migration.</description></item>
|
||||
/// <item><description>30000003: First version after converting legacy total score to standardised.</description></item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public const int LATEST_VERSION = 30000003;
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Scoring
|
||||
if (StandardisedScoreMigrationTools.ShouldMigrateToNewStandardised(model))
|
||||
model.TotalScore = StandardisedScoreMigrationTools.GetNewStandardised(model);
|
||||
else if (model.IsLegacyScore)
|
||||
model.TotalScore = ConvertFromLegacyTotalScore(model);
|
||||
model.TotalScore = StandardisedScoreMigrationTools.ConvertFromLegacyTotalScore(model, beatmaps());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -153,65 +153,6 @@ namespace osu.Game.Scoring
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
public long ConvertFromLegacyTotalScore(ScoreInfo score)
|
||||
{
|
||||
if (!score.IsLegacyScore)
|
||||
return score.TotalScore;
|
||||
|
||||
var beatmap = beatmaps().GetWorkingBeatmap(score.BeatmapInfo);
|
||||
var ruleset = score.Ruleset.CreateInstance();
|
||||
|
||||
var sv1Processor = ruleset.CreateLegacyScoreProcessor();
|
||||
if (sv1Processor == null)
|
||||
return score.TotalScore;
|
||||
|
||||
sv1Processor.Simulate(beatmap, beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, score.Mods), score.Mods);
|
||||
|
||||
int maximumLegacyAccuracyScore = sv1Processor.AccuracyScore;
|
||||
int maximumLegacyComboScore = sv1Processor.ComboScore;
|
||||
double maximumLegacyBonusRatio = sv1Processor.BonusScoreRatio;
|
||||
double modMultiplier = score.Mods.Select(m => m.ScoreMultiplier).Aggregate(1.0, (c, n) => c * n);
|
||||
|
||||
// The part of total score that doesn't include bonus.
|
||||
int maximumLegacyBaseScore = maximumLegacyAccuracyScore + maximumLegacyComboScore;
|
||||
|
||||
// The combo proportion is calculated as a proportion of maximumLegacyBaseScore.
|
||||
double comboProportion = Math.Min(1, (double)score.LegacyTotalScore / maximumLegacyBaseScore);
|
||||
|
||||
// The bonus proportion makes up the rest of the score that exceeds maximumLegacyBaseScore.
|
||||
double bonusProportion = Math.Max(0, (score.LegacyTotalScore - maximumLegacyBaseScore) * maximumLegacyBonusRatio);
|
||||
|
||||
switch (ruleset.RulesetInfo.OnlineID)
|
||||
{
|
||||
case 0:
|
||||
return (long)Math.Round((
|
||||
700000 * comboProportion
|
||||
+ 300000 * Math.Pow(score.Accuracy, 10)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 1:
|
||||
return (long)Math.Round((
|
||||
250000 * comboProportion
|
||||
+ 750000 * Math.Pow(score.Accuracy, 3.6)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 2:
|
||||
return (long)Math.Round((
|
||||
600000 * comboProportion
|
||||
+ 400000 * score.Accuracy
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
case 3:
|
||||
return (long)Math.Round((
|
||||
990000 * comboProportion
|
||||
+ 10000 * Math.Pow(score.Accuracy, 2 + 2 * score.Accuracy)
|
||||
+ bonusProportion) * modMultiplier);
|
||||
|
||||
default:
|
||||
return score.TotalScore;
|
||||
}
|
||||
}
|
||||
|
||||
// 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>();
|
||||
|
||||
|
@ -57,6 +57,9 @@ namespace osu.Game.Scoring
|
||||
/// <summary>
|
||||
/// Used to preserve the total score for legacy scores.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Not populated if <see cref="IsLegacyScore"/> is <c>false</c>.
|
||||
/// </remarks>
|
||||
public long LegacyTotalScore { get; set; }
|
||||
|
||||
public int MaxCombo { get; set; }
|
||||
@ -69,6 +72,14 @@ namespace osu.Game.Scoring
|
||||
|
||||
public double? PP { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The version of this score as stored in the database.
|
||||
/// If this does not match <see cref="LegacyScoreEncoder.LATEST_VERSION"/>,
|
||||
/// then the score has not yet been updated to reflect the current scoring values.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This may not match the version stored in the replay files.
|
||||
/// </remarks>
|
||||
public int Version { get; set; } = LegacyScoreEncoder.LATEST_VERSION;
|
||||
|
||||
[Indexed]
|
||||
|
@ -169,8 +169,6 @@ namespace osu.Game.Scoring
|
||||
/// <param name="score">The score to populate the statistics of.</param>
|
||||
public void PopulateMaximumStatistics(ScoreInfo score) => scoreImporter.PopulateMaximumStatistics(score);
|
||||
|
||||
public long ConvertFromLegacyTotalScore(ScoreInfo score) => scoreImporter.ConvertFromLegacyTotalScore(score);
|
||||
|
||||
#region Implementation of IPresentImports<ScoreInfo>
|
||||
|
||||
public Action<IEnumerable<Live<ScoreInfo>>> PresentImport
|
||||
|
Loading…
Reference in New Issue
Block a user