1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 18:07:23 +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
{
protected const double MAX_SCORE = 1000000;
public const double MAX_SCORE = 1000000;
private const double accuracy_cutoff_x = 1;
private const double accuracy_cutoff_s = 0.95;
@ -76,11 +76,6 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
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>
/// The <see cref="HitEvent"/>s collected during gameplay thus far.
/// Intended for use with various statistics displays.
@ -173,7 +168,6 @@ namespace osu.Game.Rulesets.Scoring
Rank.Value = mod.AdjustRank(Rank.Value, accuracy.NewValue);
};
Mode.ValueChanged += _ => updateScore();
Mods.ValueChanged += mods =>
{
ScoreMultiplier = 1;
@ -278,45 +272,7 @@ namespace osu.Game.Rulesets.Scoring
private void updateScore()
{
Accuracy.Value = currentMaxBasicScore > 0 ? currentBasicScore / currentMaxBasicScore : 1;
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);
TotalScore.Value = (long)Math.Round(ComputeTotalScore());
}
protected abstract double ComputeTotalScore();

View File

@ -3,13 +3,58 @@
#nullable disable
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring.Legacy
{
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)
{
switch (scoreInfo.Ruleset.OnlineID)

View File

@ -20,6 +20,7 @@ using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring;
using osu.Game.Online.API;
using osu.Game.Scoring.Legacy;
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="mode">The <see cref="ScoringMode"/> to return the total score as.</param>
/// <returns>The total score.</returns>
public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised)
{
// 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);
}
public long GetTotalScore([NotNull] ScoreInfo score, ScoringMode mode = ScoringMode.Standardised) => score.GetDisplayScore(mode);
/// <summary>
/// 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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Scoring;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osu.Game.Utils;
@ -55,6 +57,7 @@ namespace osu.Game.Screens.Play.HUD
public BindableInt Combo { get; } = new BindableInt();
public BindableBool HasQuit { get; } = new BindableBool();
public Bindable<long> DisplayOrder { get; } = new Bindable<long>();
public Func<ScoringMode, long> GetDisplayScore { get; set; }
public Color4? BackgroundColour { get; set; }
@ -100,6 +103,8 @@ namespace osu.Game.Screens.Play.HUD
private Container scoreComponents;
private IBindable<ScoringMode> scoreDisplayMode;
/// <summary>
/// Creates a new <see cref="GameplayLeaderboardScore"/>.
/// </summary>
@ -112,10 +117,12 @@ namespace osu.Game.Screens.Play.HUD
AutoSizeAxes = Axes.X;
Height = PANEL_HEIGHT;
GetDisplayScore = _ => TotalScore.Value;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
private void load(OsuColour colours, OsuConfigManager osuConfigManager)
{
Container avatarContainer;
@ -286,7 +293,9 @@ namespace osu.Game.Screens.Play.HUD
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 =>
{
@ -303,6 +312,11 @@ namespace osu.Game.Screens.Play.HUD
HasQuit.BindValueChanged(_ => updateState());
}
private void updateScore()
{
scoreText.Text = GetDisplayScore(scoreDisplayMode.Value).ToString("N0");
}
protected override void LoadComplete()
{
base.LoadComplete();

View File

@ -9,12 +9,14 @@ using osu.Framework.Bindables;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring.Legacy;
namespace osu.Game.Screens.Play.HUD
{
public abstract partial class GameplayScoreCounter : ScoreCounter
{
private Bindable<ScoringMode> scoreDisplayMode;
private Bindable<long> totalScoreBindable;
protected GameplayScoreCounter()
: base(6)
@ -42,7 +44,8 @@ namespace osu.Game.Screens.Play.HUD
}
}, 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
using System;
using osu.Framework.Bindables;
using osu.Game.Rulesets.Scoring;
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.
/// </summary>
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.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
@ -10,6 +9,7 @@ using osu.Game.Configuration;
using osu.Game.Online.API.Requests;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Scoring.Legacy;
using osu.Game.Screens.Select;
using osu.Game.Users;
@ -27,15 +27,9 @@ namespace osu.Game.Screens.Play.HUD
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]
private ScoreProcessor scoreProcessor { get; set; } = null!;
[Resolved]
private ScoreManager scoreManager { get; set; } = null!;
/// <summary>
/// Whether the leaderboard should be visible regardless of the configuration value.
/// This is true by default, but can be changed.
@ -70,7 +64,6 @@ namespace osu.Game.Screens.Play.HUD
private void showScores()
{
Clear();
scoreBindables.Clear();
if (!Scores.Any())
return;
@ -79,12 +72,8 @@ namespace osu.Game.Screens.Play.HUD
{
var score = Add(s.User, false);
var bindableTotal = scoreManager.GetBindableTotalScore(s);
// 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.GetDisplayScore = s.GetDisplayScore;
score.TotalScore.Value = s.TotalScore;
score.Accuracy.Value = s.Accuracy;
score.Combo.Value = s.MaxCombo;
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);
local.GetDisplayScore = scoreProcessor.GetDisplayScore;
local.TotalScore.BindTarget = scoreProcessor.TotalScore;
local.Accuracy.BindTarget = scoreProcessor.Accuracy;
local.Combo.BindTarget = scoreProcessor.HighestCombo;

View File

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