1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-27 14:52:55 +08:00

Implement basic score recalculation

This commit is contained in:
smoogipoo 2020-08-28 19:16:46 +09:00
parent 85bda29b71
commit 4d15f0fe52
6 changed files with 55 additions and 16 deletions

View File

@ -201,11 +201,11 @@ namespace osu.Game.Beatmaps
var calculator = ruleset.CreateDifficultyCalculator(beatmapManager.GetWorkingBeatmap(beatmapInfo)); var calculator = ruleset.CreateDifficultyCalculator(beatmapManager.GetWorkingBeatmap(beatmapInfo));
var attributes = calculator.Calculate(key.Mods); var attributes = calculator.Calculate(key.Mods);
return difficultyCache[key] = new StarDifficulty(attributes.StarRating); return difficultyCache[key] = new StarDifficulty(attributes.StarRating, attributes.MaxCombo);
} }
catch catch
{ {
return difficultyCache[key] = new StarDifficulty(0); return difficultyCache[key] = new StarDifficulty();
} }
} }
@ -227,7 +227,7 @@ namespace osu.Game.Beatmaps
if (beatmapInfo.ID == 0 || rulesetInfo.ID == null) if (beatmapInfo.ID == 0 || rulesetInfo.ID == null)
{ {
// If not, fall back to the existing star difficulty (e.g. from an online source). // If not, fall back to the existing star difficulty (e.g. from an online source).
existingDifficulty = new StarDifficulty(beatmapInfo.StarDifficulty); existingDifficulty = new StarDifficulty(beatmapInfo.StarDifficulty, beatmapInfo.MaxCombo ?? 0);
key = default; key = default;
return true; return true;
@ -292,10 +292,12 @@ namespace osu.Game.Beatmaps
public readonly struct StarDifficulty public readonly struct StarDifficulty
{ {
public readonly double Stars; public readonly double Stars;
public readonly int MaxCombo;
public StarDifficulty(double stars) public StarDifficulty(double stars, int maxCombo)
{ {
Stars = stars; Stars = stars;
MaxCombo = maxCombo;
// Todo: Add more members (BeatmapInfo.DifficultyRating? Attributes? Etc...) // Todo: Add more members (BeatmapInfo.DifficultyRating? Attributes? Etc...)
} }

View File

@ -72,7 +72,7 @@ namespace osu.Game.Online.Leaderboards
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(IAPIProvider api, OsuColour colour) private void load(IAPIProvider api, OsuColour colour, ScoreManager scoreManager)
{ {
var user = score.User; var user = score.User;
@ -194,7 +194,7 @@ namespace osu.Game.Online.Leaderboards
{ {
TextColour = Color4.White, TextColour = Color4.White,
GlowColour = Color4Extensions.FromHex(@"83ccfa"), GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = score.TotalScore.ToString(@"N0"), Text = scoreManager.GetTotalScore(score).ToString(@"N0"),
Font = OsuFont.Numeric.With(size: 23), Font = OsuFont.Numeric.With(size: 23),
}, },
RankContainer = new Container RankContainer = new Container

View File

@ -57,6 +57,8 @@ namespace osu.Game
protected ScoreManager ScoreManager; protected ScoreManager ScoreManager;
protected BeatmapDifficultyManager DifficultyManager;
protected SkinManager SkinManager; protected SkinManager SkinManager;
protected RulesetStore RulesetStore; protected RulesetStore RulesetStore;
@ -194,7 +196,7 @@ namespace osu.Game
dependencies.Cache(FileStore = new FileStore(contextFactory, Storage)); dependencies.Cache(FileStore = new FileStore(contextFactory, Storage));
// ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup() // ordering is important here to ensure foreign keys rules are not broken in ModelStore.Cleanup()
dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host)); dependencies.Cache(ScoreManager = new ScoreManager(RulesetStore, () => BeatmapManager, Storage, API, contextFactory, Host, () => DifficultyManager));
dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap)); dependencies.Cache(BeatmapManager = new BeatmapManager(Storage, contextFactory, RulesetStore, API, Audio, Host, defaultBeatmap));
// this should likely be moved to ArchiveModelManager when another case appers where it is necessary // this should likely be moved to ArchiveModelManager when another case appers where it is necessary
@ -218,9 +220,8 @@ namespace osu.Game
ScoreManager.Undelete(getBeatmapScores(item), true); ScoreManager.Undelete(getBeatmapScores(item), true);
}); });
var difficultyManager = new BeatmapDifficultyManager(); dependencies.Cache(DifficultyManager = new BeatmapDifficultyManager());
dependencies.Cache(difficultyManager); AddInternal(DifficultyManager);
AddInternal(difficultyManager);
dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(contextFactory, RulesetStore));
dependencies.Cache(SettingsStore = new SettingsStore(contextFactory)); dependencies.Cache(SettingsStore = new SettingsStore(contextFactory));

View File

@ -25,6 +25,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
private const float row_height = 22; private const float row_height = 22;
private const int text_size = 12; private const int text_size = 12;
[Resolved]
private ScoreManager scoreManager { get; set; }
private readonly FillFlowContainer backgroundFlow; private readonly FillFlowContainer backgroundFlow;
private Color4 highAccuracyColour; private Color4 highAccuracyColour;
@ -121,7 +124,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
new OsuSpriteText new OsuSpriteText
{ {
Margin = new MarginPadding { Right = horizontal_inset }, Margin = new MarginPadding { Right = horizontal_inset },
Text = $@"{score.TotalScore:N0}", Text = $@"{scoreManager.GetTotalScore(score):N0}",
Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium) Font = OsuFont.GetFont(size: text_size, weight: index == 0 ? FontWeight.Bold : FontWeight.Medium)
}, },
new OsuSpriteText new OsuSpriteText

View File

@ -203,19 +203,24 @@ namespace osu.Game.Rulesets.Scoring
} }
private double getScore(ScoringMode mode) private double getScore(ScoringMode mode)
{
return GetScore(baseScore / maxBaseScore, HighestCombo.Value / maxHighestCombo, bonusScore, mode);
}
public double GetScore(double accuracyRatio, double comboRatio, double bonus, ScoringMode mode)
{ {
switch (mode) switch (mode)
{ {
default: default:
case ScoringMode.Standardised: case ScoringMode.Standardised:
double accuracyScore = accuracyPortion * baseScore / maxBaseScore; double accuracyScore = accuracyPortion * accuracyRatio;
double comboScore = comboPortion * HighestCombo.Value / maxHighestCombo; double comboScore = comboPortion * comboRatio;
return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier; return (max_score * (accuracyScore + comboScore) + bonus) * scoreMultiplier;
case ScoringMode.Classic: case ScoringMode.Classic:
// should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1) // should emulate osu-stable's scoring as closely as we can (https://osu.ppy.sh/help/wiki/Score/ScoreV1)
return bonusScore + baseScore * (1 + Math.Max(0, HighestCombo.Value - 1) * scoreMultiplier / 25); return bonus + (accuracyRatio * maxBaseScore) * (1 + Math.Max(0, (comboRatio * maxHighestCombo) - 1) * scoreMultiplier / 25);
} }
} }

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions; using System.Linq.Expressions;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Platform; using osu.Framework.Platform;
@ -15,6 +16,7 @@ using osu.Game.IO.Archives;
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.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring.Legacy; using osu.Game.Scoring.Legacy;
namespace osu.Game.Scoring namespace osu.Game.Scoring
@ -30,11 +32,16 @@ namespace osu.Game.Scoring
private readonly RulesetStore rulesets; private readonly RulesetStore rulesets;
private readonly Func<BeatmapManager> beatmaps; private readonly Func<BeatmapManager> beatmaps;
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null) [CanBeNull]
private readonly Func<BeatmapDifficultyManager> difficulties;
public ScoreManager(RulesetStore rulesets, Func<BeatmapManager> beatmaps, Storage storage, IAPIProvider api, IDatabaseContextFactory contextFactory, IIpcHost importHost = null,
Func<BeatmapDifficultyManager> difficulties = null)
: base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost) : base(storage, contextFactory, api, new ScoreStore(contextFactory, storage), importHost)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
this.difficulties = difficulties;
} }
protected override ScoreInfo CreateModel(ArchiveReader archive) protected override ScoreInfo CreateModel(ArchiveReader archive)
@ -72,5 +79,26 @@ namespace osu.Game.Scoring
protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items) protected override bool CheckLocalAvailability(ScoreInfo model, IQueryable<ScoreInfo> items)
=> base.CheckLocalAvailability(model, items) => base.CheckLocalAvailability(model, items)
|| (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID)); || (model.OnlineScoreID != null && items.Any(i => i.OnlineScoreID == model.OnlineScoreID));
public long GetTotalScore(ScoreInfo score)
{
int? beatmapMaxCombo = score.Beatmap.MaxCombo;
if (beatmapMaxCombo == null)
{
if (score.Beatmap.ID == 0 || difficulties == null)
return score.TotalScore; // Can't do anything.
// We can compute the max combo locally.
beatmapMaxCombo = difficulties().GetDifficulty(score.Beatmap, score.Ruleset, score.Mods).MaxCombo;
}
var ruleset = score.Ruleset.CreateInstance();
var scoreProcessor = ruleset.CreateScoreProcessor();
scoreProcessor.Mods.Value = score.Mods;
return (long)Math.Round(scoreProcessor.GetScore(score.Accuracy, (double)score.MaxCombo / beatmapMaxCombo.Value, 0, ScoringMode.Standardised));
}
} }
} }