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.RulesetID = score.ScoreInfo.RulesetID;
currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray(); currentState.Mods = score.ScoreInfo.Mods.Select(m => new APIMod(m)).ToArray();
currentState.State = SpectatedUserState.Playing; currentState.State = SpectatedUserState.Playing;
currentState.MaxAchievableCombo = state.ScoreProcessor.MaxAchievableCombo;
currentState.MaxAchievableBaseScore = state.ScoreProcessor.MaxAchievableBaseScore;
currentState.TotalBasicHitObjects = state.ScoreProcessor.TotalBasicHitObjects;
currentBeatmap = state.Beatmap; currentBeatmap = state.Beatmap;
currentScore = score; currentScore = score;

View File

@ -27,6 +27,24 @@ namespace osu.Game.Online.Spectator
[Key(3)] [Key(3)]
public SpectatedUserState State { get; set; } 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) public bool Equals(SpectatorState other)
{ {
if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(null, other)) return false;

View File

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

View File

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

View File

@ -237,7 +237,7 @@ namespace osu.Game.Screens.Play
Score.ScoreInfo.Ruleset = ruleset.RulesetInfo; Score.ScoreInfo.Ruleset = ruleset.RulesetInfo;
Score.ScoreInfo.Mods = gameplayMods; 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); var rulesetSkinProvider = new RulesetSkinProvidingContainer(ruleset, playableBeatmap, Beatmap.Value.Skin);