1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 20:07:25 +08:00

Remove ScoreManager.Mode, handle per-use

This commit is contained in:
Dan Balasescu 2023-05-18 18:53:43 +09:00
parent 829e47d30b
commit 510b8e4c78
8 changed files with 77 additions and 76 deletions

View File

@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Scoring
{ {
public abstract partial class ScoreProcessor : JudgementProcessor public abstract partial class ScoreProcessor : JudgementProcessor
{ {
protected const double MAX_SCORE = 1000000; public const double MAX_SCORE = 1000000;
private const double accuracy_cutoff_x = 1; private const double accuracy_cutoff_x = 1;
private const double accuracy_cutoff_s = 0.95; private const double accuracy_cutoff_s = 0.95;
@ -76,11 +76,6 @@ namespace osu.Game.Rulesets.Scoring
/// </summary> /// </summary>
public readonly BindableInt HighestCombo = new BindableInt(); public readonly BindableInt HighestCombo = new BindableInt();
/// <summary>
/// The <see cref="ScoringMode"/> used to calculate scores.
/// </summary>
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>();
/// <summary> /// <summary>
/// The <see cref="HitEvent"/>s collected during gameplay thus far. /// The <see cref="HitEvent"/>s collected during gameplay thus far.
/// Intended for use with various statistics displays. /// Intended for use with various statistics displays.
@ -173,7 +168,6 @@ namespace osu.Game.Rulesets.Scoring
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue); Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
}; };
Mode.ValueChanged += _ => updateScore();
Mods.ValueChanged += mods => Mods.ValueChanged += mods =>
{ {
ScoreMultiplier = 1; ScoreMultiplier = 1;
@ -278,45 +272,7 @@ namespace osu.Game.Rulesets.Scoring
private void updateScore() private void updateScore()
{ {
Accuracy.Value = currentMaxBasicScore > 0 ? currentBasicScore / currentMaxBasicScore : 1; Accuracy.Value = currentMaxBasicScore > 0 ? currentBasicScore / currentMaxBasicScore : 1;
TotalScore.Value = (long)Math.Round(ComputeTotalScore());
long standardisedScore = (long)Math.Round(ComputeTotalScore());
TotalScore.Value = Mode.Value == ScoringMode.Standardised
? standardisedScore
: convertToClassic(standardisedScore, MaxBasicJudgements, ClassicScoreMultiplier);
}
/// <summary>
/// Retrieves the total score from a <see cref="ScoreInfo"/> in the given scoring mode.
/// </summary>
/// <param name="mode">The mode to return the total score in.</param>
/// <param name="scoreInfo">The score to get the total score of.</param>
/// <returns>The total score.</returns>
public long ComputeScore(ScoringMode mode, ScoreInfo scoreInfo)
{
int maxBasicJudgements = scoreInfo.MaximumStatistics.Where(k => k.Key.IsBasic())
.Select(k => k.Value)
.DefaultIfEmpty(0)
.Sum();
return mode == ScoringMode.Standardised
? scoreInfo.TotalScore
: convertToClassic(scoreInfo.TotalScore, maxBasicJudgements, ClassicScoreMultiplier);
}
/// <summary>
/// Converts a standardised total score to the classic score.
/// </summary>
/// <param name="score">The standardised score.</param>
/// <param name="maxBasicJudgements">The maximum possible number of basic judgements.</param>
/// <param name="classicMultiplier">The classic multiplier.</param>
/// <returns>The classic score.</returns>
private static long convertToClassic(long score, int maxBasicJudgements, double classicMultiplier)
{
// This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring.
// The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes.
double scaledRawScore = score / MAX_SCORE;
return (long)Math.Round(Math.Pow(scaledRawScore * Math.Max(1, maxBasicJudgements), 2) * classicMultiplier);
} }
protected abstract double ComputeTotalScore(); protected abstract double ComputeTotalScore();

View File

@ -3,13 +3,58 @@
#nullable disable #nullable disable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring.Legacy namespace osu.Game.Scoring.Legacy
{ {
public static class ScoreInfoExtensions public static class ScoreInfoExtensions
{ {
public static long GetDisplayScore(this ScoreProcessor scoreProcessor, ScoringMode mode)
=> getDisplayScore(scoreProcessor.Ruleset.RulesetInfo.OnlineID, scoreProcessor.TotalScore.Value, mode, scoreProcessor.MaximumStatistics);
public static long GetDisplayScore(this ScoreInfo scoreInfo, ScoringMode mode)
=> getDisplayScore(scoreInfo.Ruleset.OnlineID, scoreInfo.TotalScore, mode, scoreInfo.MaximumStatistics);
private static long getDisplayScore(int rulesetId, long score, ScoringMode mode, IReadOnlyDictionary<HitResult, int> maximumStatistics)
{
if (mode == ScoringMode.Standardised)
return score;
double multiplier;
switch (rulesetId)
{
case 0:
multiplier = 36;
break;
case 1:
multiplier = 22;
break;
case 2:
multiplier = 28;
break;
case 3:
multiplier = 16;
break;
default:
return score;
}
int maxBasicJudgements = maximumStatistics.Where(k => k.Key.IsBasic()).Select(k => k.Value).DefaultIfEmpty(0).Sum();
// This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring.
// The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes.
double scaledRawScore = score / ScoreProcessor.MAX_SCORE;
return (long)Math.Round(Math.Pow(scaledRawScore * Math.Max(1, maxBasicJudgements), 2) * multiplier);
}
public static int? GetCountGeki(this ScoreInfo scoreInfo) public static int? GetCountGeki(this ScoreInfo scoreInfo)
{ {
switch (scoreInfo.Ruleset.OnlineID) switch (scoreInfo.Ruleset.OnlineID)

View File

@ -20,6 +20,7 @@ using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Scoring.Legacy;
namespace osu.Game.Scoring namespace osu.Game.Scoring
{ {
@ -105,16 +106,7 @@ namespace osu.Game.Scoring
/// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param> /// <param name="score">The <see cref="ScoreInfo"/> to calculate the total score of.</param>
/// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param> /// <param name="mode">The <see cref="ScoringMode"/> to return the total score as.</param>
/// <returns>The total score.</returns> /// <returns>The total score.</returns>
public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => score.GetDisplayScore(mode);
{
// Shortcut to avoid potentially creating many ruleset objects in the default scoring mode.
if (mode == ScoringMode.Standardised)
return score.TotalScore;
return score.Ruleset.CreateInstance()
.CreateScoreProcessor()
.ComputeScore(mode, score);
}
/// <summary> /// <summary>
/// Retrieves the maximum achievable combo for the provided score. /// Retrieves the maximum achievable combo for the provided score.

View File

@ -11,8 +11,10 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Configuration;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users; using osu.Game.Users;
using osu.Game.Users.Drawables; using osu.Game.Users.Drawables;
using osu.Game.Utils; using osu.Game.Utils;
@ -55,6 +57,7 @@ namespace osu.Game.Screens.Play.HUD
public BindableInt Combo { get; } = new BindableInt(); public BindableInt Combo { get; } = new BindableInt();
public BindableBool HasQuit { get; } = new BindableBool(); public BindableBool HasQuit { get; } = new BindableBool();
public Bindable<long> DisplayOrder { get; } = new Bindable<long>(); public Bindable<long> DisplayOrder { get; } = new Bindable<long>();
public Func<ScoringMode, long> GetDisplayScore { get; set; }
public Color4? BackgroundColour { get; set; } public Color4? BackgroundColour { get; set; }
@ -100,6 +103,8 @@ namespace osu.Game.Screens.Play.HUD
private Container scoreComponents; private Container scoreComponents;
private IBindable<ScoringMode> scoreDisplayMode;
/// <summary> /// <summary>
/// Creates a new <see cref="GameplayLeaderboardScore"/>. /// Creates a new <see cref="GameplayLeaderboardScore"/>.
/// </summary> /// </summary>
@ -112,10 +117,12 @@ namespace osu.Game.Screens.Play.HUD
AutoSizeAxes = Axes.X; AutoSizeAxes = Axes.X;
Height = PANEL_HEIGHT; Height = PANEL_HEIGHT;
GetDisplayScore = _ => TotalScore.Value;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours, OsuConfigManager osuConfigManager)
{ {
Container avatarContainer; Container avatarContainer;
@ -286,7 +293,9 @@ namespace osu.Game.Screens.Play.HUD
LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add); LoadComponentAsync(new DrawableAvatar(User), avatarContainer.Add);
TotalScore.BindValueChanged(v => scoreText.Text = v.NewValue.ToString("N0"), true); scoreDisplayMode = osuConfigManager.GetBindable<ScoringMode>(OsuSetting.ScoreDisplayMode);
scoreDisplayMode.BindValueChanged(_ => updateScore());
TotalScore.BindValueChanged(_ => updateScore(), true);
Accuracy.BindValueChanged(v => Accuracy.BindValueChanged(v =>
{ {
@ -303,6 +312,11 @@ namespace osu.Game.Screens.Play.HUD
HasQuit.BindValueChanged(_ => updateState()); HasQuit.BindValueChanged(_ => updateState());
} }
private void updateScore()
{
scoreText.Text = GetDisplayScore(scoreDisplayMode.Value).ToString("N0");
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();

View File

@ -9,12 +9,14 @@ using osu.Framework.Bindables;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring.Legacy;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
public abstract partial class GameplayScoreCounter : ScoreCounter public abstract partial class GameplayScoreCounter : ScoreCounter
{ {
private Bindable<ScoringMode> scoreDisplayMode; private Bindable<ScoringMode> scoreDisplayMode;
private Bindable<long> totalScoreBindable;
protected GameplayScoreCounter() protected GameplayScoreCounter()
: base(6) : base(6)
@ -42,7 +44,8 @@ namespace osu.Game.Screens.Play.HUD
} }
}, true); }, true);
Current.BindTo(scoreProcessor.TotalScore); totalScoreBindable = scoreProcessor.TotalScore.GetBoundCopy();
totalScoreBindable.BindValueChanged(_ => Current.Value = scoreProcessor.GetDisplayScore(scoreDisplayMode.Value), true);
} }
} }
} }

View File

@ -3,7 +3,9 @@
#nullable disable #nullable disable
using System;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Screens.Play.HUD namespace osu.Game.Screens.Play.HUD
{ {
@ -20,5 +22,7 @@ namespace osu.Game.Screens.Play.HUD
/// Lower numbers will appear higher in cases of <see cref="TotalScore"/> ties. /// Lower numbers will appear higher in cases of <see cref="TotalScore"/> ties.
/// </summary> /// </summary>
Bindable<long> DisplayOrder { get; } Bindable<long> DisplayOrder { get; }
Func<ScoringMode, long> GetDisplayScore { get; set; }
} }
} }

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -10,6 +9,7 @@ using osu.Game.Configuration;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring; using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
using osu.Game.Screens.Select; using osu.Game.Screens.Select;
using osu.Game.Users; using osu.Game.Users;
@ -27,15 +27,9 @@ namespace osu.Game.Screens.Play.HUD
public readonly IBindableList<ScoreInfo> Scores = new BindableList<ScoreInfo>(); public readonly IBindableList<ScoreInfo> Scores = new BindableList<ScoreInfo>();
// hold references to ensure bindables are updated.
private readonly List<Bindable<long>> scoreBindables = new List<Bindable<long>>();
[Resolved] [Resolved]
private ScoreProcessor scoreProcessor { get; set; } = null!; private ScoreProcessor scoreProcessor { get; set; } = null!;
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
/// <summary> /// <summary>
/// Whether the leaderboard should be visible regardless of the configuration value. /// Whether the leaderboard should be visible regardless of the configuration value.
/// This is true by default, but can be changed. /// This is true by default, but can be changed.
@ -70,7 +64,6 @@ namespace osu.Game.Screens.Play.HUD
private void showScores() private void showScores()
{ {
Clear(); Clear();
scoreBindables.Clear();
if (!Scores.Any()) if (!Scores.Any())
return; return;
@ -79,12 +72,8 @@ namespace osu.Game.Screens.Play.HUD
{ {
var score = Add(s.User, false); var score = Add(s.User, false);
var bindableTotal = scoreManager.GetBindableTotalScore(s); score.GetDisplayScore = s.GetDisplayScore;
score.TotalScore.Value = s.TotalScore;
// Direct binding not possible due to differing types (see https://github.com/ppy/osu/issues/20298).
bindableTotal.BindValueChanged(total => score.TotalScore.Value = total.NewValue, true);
scoreBindables.Add(bindableTotal);
score.Accuracy.Value = s.Accuracy; score.Accuracy.Value = s.Accuracy;
score.Combo.Value = s.MaxCombo; score.Combo.Value = s.MaxCombo;
score.DisplayOrder.Value = s.OnlineID > 0 ? s.OnlineID : s.Date.ToUnixTimeSeconds(); score.DisplayOrder.Value = s.OnlineID > 0 ? s.OnlineID : s.Date.ToUnixTimeSeconds();
@ -92,6 +81,7 @@ namespace osu.Game.Screens.Play.HUD
ILeaderboardScore local = Add(trackingUser, true); ILeaderboardScore local = Add(trackingUser, true);
local.GetDisplayScore = scoreProcessor.GetDisplayScore;
local.TotalScore.BindTarget = scoreProcessor.TotalScore; local.TotalScore.BindTarget = scoreProcessor.TotalScore;
local.Accuracy.BindTarget = scoreProcessor.Accuracy; local.Accuracy.BindTarget = scoreProcessor.Accuracy;
local.Combo.BindTarget = scoreProcessor.HighestCombo; local.Combo.BindTarget = scoreProcessor.HighestCombo;

View File

@ -237,9 +237,6 @@ namespace osu.Game.Screens.Play
dependencies.CacheAs(HealthProcessor); dependencies.CacheAs(HealthProcessor);
if (!ScoreProcessor.Mode.Disabled)
config.BindWith(OsuSetting.ScoreDisplayMode, ScoreProcessor.Mode);
InternalChild = GameplayClockContainer = CreateGameplayClockContainer(Beatmap.Value, DrawableRuleset.GameplayStartTime); InternalChild = GameplayClockContainer = CreateGameplayClockContainer(Beatmap.Value, DrawableRuleset.GameplayStartTime);
AddInternal(screenSuspension = new ScreenSuspensionHandler(GameplayClockContainer)); AddInternal(screenSuspension = new ScreenSuspensionHandler(GameplayClockContainer));