1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-25 11:47:19 +08:00

Send ScoreProcessor statistics in SpectatorState

This commit is contained in:
Dan Balasescu 2022-05-30 19:14:03 +09:00
parent c97b477485
commit a052e09ac3
5 changed files with 61 additions and 33 deletions

View File

@ -172,6 +172,9 @@ namespace osu.Game.Online.Spectator
currentState.RulesetID = score.ScoreInfo.RulesetID;
currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray();
currentState.State = SpectatedUserState.Playing;
currentState.MaxAchievableCombo = state.ScoreProcessor.MaxAchievableCombo;
currentState.MaxAchievableBaseScore = state.ScoreProcessor.MaxAchievableBaseScore;
currentState.TotalBasicHitObjects = state.ScoreProcessor.TotalBasicHitObjects;
currentBeatmap = state.Beatmap;
currentScore = score;

View File

@ -27,6 +27,24 @@ namespace osu.Game.Online.Spectator
[Key(3)]
public SpectatedUserState State { get; set; }
/// <summary>
/// The maximum achievable combo, if everything is hit perfectly.
/// </summary>
[Key(4)]
public int MaxAchievableCombo { get; set; }
/// <summary>
/// The maximum achievable base score, if everything is hit perfectly.
/// </summary>
[Key(5)]
public double MaxAchievableBaseScore { get; set; }
/// <summary>
/// The total number of basic (non-tick and non-bonus) hitobjects that can be hit.
/// </summary>
[Key(6)]
public int TotalBasicHitObjects { get; set; }
public bool Equals(SpectatorState other)
{
if (ReferenceEquals(null, other)) return false;

View File

@ -88,17 +88,20 @@ namespace osu.Game.Rulesets.Scoring
private readonly double accuracyPortion;
private readonly double comboPortion;
private int maxAchievableCombo;
/// <summary>
/// The maximum achievable combo, if everything is hit perfectly.
/// </summary>
internal int MaxAchievableCombo;
/// <summary>
/// The maximum achievable base score.
/// The maximum achievable base score, if everything is hit perfectly.
/// </summary>
private double maxBaseScore;
internal double MaxAchievableBaseScore;
/// <summary>
/// The maximum number of basic (non-tick and non-bonus) hitobjects.
/// The total number of basic (non-tick and non-bonus) hitobjects that can be hit.
/// </summary>
private int maxBasicHitObjects;
internal int TotalBasicHitObjects;
/// <summary>
/// The maximum <see cref="HitResult"/> of a basic (non-tick and non-bonus) hitobject.
@ -106,9 +109,9 @@ namespace osu.Game.Rulesets.Scoring
/// </summary>
private HitResult? maxBasicResult;
private double rollingMaxBaseScore;
private double baseScore;
private int basicHitObjects;
private double rollingMaxAchievableBaseScore;
private double rollingBaseScore;
private int rollingBasicHitObjects;
private bool beatmapApplied;
private readonly Dictionary<HitResult, int> scoreResultCounts = new Dictionary<HitResult, int>();
@ -175,12 +178,12 @@ namespace osu.Game.Rulesets.Scoring
if (!result.Type.IsBonus())
{
baseScore += scoreIncrease;
rollingMaxBaseScore += result.Judgement.MaxNumericResult;
rollingBaseScore += scoreIncrease;
rollingMaxAchievableBaseScore += result.Judgement.MaxNumericResult;
}
if (result.Type.IsBasic())
basicHitObjects++;
rollingBasicHitObjects++;
hitEvents.Add(CreateHitEvent(result));
lastHitObject = result.HitObject;
@ -213,12 +216,12 @@ namespace osu.Game.Rulesets.Scoring
if (!result.Type.IsBonus())
{
baseScore -= scoreIncrease;
rollingMaxBaseScore -= result.Judgement.MaxNumericResult;
rollingBaseScore -= scoreIncrease;
rollingMaxAchievableBaseScore -= result.Judgement.MaxNumericResult;
}
if (result.Type.IsBasic())
basicHitObjects--;
rollingBasicHitObjects--;
Debug.Assert(hitEvents.Count > 0);
lastHitObject = hitEvents[^1].LastHitObject;
@ -229,12 +232,12 @@ namespace osu.Game.Rulesets.Scoring
private void updateScore()
{
double rollingAccuracyRatio = rollingMaxBaseScore > 0 ? baseScore / rollingMaxBaseScore : 1;
double accuracyRatio = maxBaseScore > 0 ? baseScore / maxBaseScore : 1;
double comboRatio = maxAchievableCombo > 0 ? (double)HighestCombo.Value / maxAchievableCombo : 1;
double rollingAccuracyRatio = rollingMaxAchievableBaseScore > 0 ? rollingBaseScore / rollingMaxAchievableBaseScore : 1;
double accuracyRatio = MaxAchievableBaseScore > 0 ? rollingBaseScore / MaxAchievableBaseScore : 1;
double comboRatio = MaxAchievableCombo > 0 ? (double)HighestCombo.Value / MaxAchievableCombo : 1;
Accuracy.Value = rollingAccuracyRatio;
TotalScore.Value = ComputeScore(Mode.Value, accuracyRatio, comboRatio, getBonusScore(scoreResultCounts), maxBasicHitObjects);
TotalScore.Value = ComputeScore(Mode.Value, accuracyRatio, comboRatio, getBonusScore(scoreResultCounts), TotalBasicHitObjects);
}
/// <summary>
@ -288,10 +291,10 @@ namespace osu.Game.Rulesets.Scoring
out _,
out _);
double accuracyRatio = maxBaseScore > 0 ? extractedBaseScore / maxBaseScore : 1;
double comboRatio = maxAchievableCombo > 0 ? (double)scoreInfo.MaxCombo / maxAchievableCombo : 1;
double accuracyRatio = MaxAchievableBaseScore > 0 ? extractedBaseScore / MaxAchievableBaseScore : 1;
double comboRatio = MaxAchievableCombo > 0 ? (double)scoreInfo.MaxCombo / MaxAchievableCombo : 1;
return ComputeScore(mode, accuracyRatio, comboRatio, getBonusScore(scoreInfo.Statistics), maxBasicHitObjects);
return ComputeScore(mode, accuracyRatio, comboRatio, getBonusScore(scoreInfo.Statistics), TotalBasicHitObjects);
}
/// <summary>
@ -403,14 +406,14 @@ namespace osu.Game.Rulesets.Scoring
if (storeResults)
{
maxAchievableCombo = HighestCombo.Value;
maxBaseScore = baseScore;
maxBasicHitObjects = basicHitObjects;
MaxAchievableCombo = HighestCombo.Value;
MaxAchievableBaseScore = rollingBaseScore;
TotalBasicHitObjects = rollingBasicHitObjects;
}
baseScore = 0;
rollingMaxBaseScore = 0;
basicHitObjects = 0;
rollingBaseScore = 0;
rollingMaxAchievableBaseScore = 0;
rollingBasicHitObjects = 0;
TotalScore.Value = 0;
Accuracy.Value = 1;
@ -444,7 +447,7 @@ namespace osu.Game.Rulesets.Scoring
if (frame.Header == null)
return;
extractFromStatistics(ruleset, frame.Header.Statistics, out baseScore, out rollingMaxBaseScore, out _, out _);
extractFromStatistics(ruleset, frame.Header.Statistics, out rollingBaseScore, out rollingMaxAchievableBaseScore, out _, out _);
HighestCombo.Value = frame.Header.MaxCombo;
scoreResultCounts.Clear();

View File

@ -1,6 +1,8 @@
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using osu.Framework.Bindables;
@ -8,10 +10,9 @@ using osu.Game.Beatmaps;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
#nullable enable
namespace osu.Game.Screens.Play
{
/// <summary>
@ -39,6 +40,8 @@ namespace osu.Game.Screens.Play
/// </summary>
public readonly Score Score;
public readonly ScoreProcessor ScoreProcessor;
/// <summary>
/// Whether gameplay completed without the user failing.
/// </summary>
@ -61,7 +64,7 @@ namespace osu.Game.Screens.Play
private readonly Bindable<JudgementResult> lastJudgementResult = new Bindable<JudgementResult>();
public GameplayState(IBeatmap beatmap, Ruleset ruleset, IReadOnlyList<Mod>? mods = null, Score? score = null)
public GameplayState(IBeatmap beatmap, Ruleset ruleset, IReadOnlyList<Mod>? mods = null, Score? score = null, ScoreProcessor? scoreProcessor = null)
{
Beatmap = beatmap;
Ruleset = ruleset;
@ -72,7 +75,8 @@ namespace osu.Game.Screens.Play
Ruleset = ruleset.RulesetInfo
}
};
Mods = mods ?? ArraySegment<Mod>.Empty;
Mods = mods ?? Array.Empty<Mod>();
ScoreProcessor = scoreProcessor ?? ruleset.CreateScoreProcessor();
}
/// <summary>

View File

@ -237,7 +237,7 @@ namespace osu.Game.Screens.Play
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods;
dependencies.CacheAs(GameplayState = new GameplayState(playableBeatmap, ruleset, gameplayMods, Score));
dependencies.CacheAs(GameplayState = new GameplayState(playableBeatmap, ruleset, gameplayMods, Score, ScoreProcessor));
var rulesetSkinProvider = new RulesetSkinProvidingContainer(ruleset, playableBeatmap, Beatmap.Value.Skin);