mirror of
https://github.com/osukey/osukey.git
synced 2025-08-06 16:13:57 +09:00
Merge pull request #21587 from smoogipoo/spectatorstate-maximum-statistics
Store maximum statistics to spectator state
This commit is contained in:
@ -117,11 +117,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
BeatmapID = 0,
|
BeatmapID = 0,
|
||||||
RulesetID = 0,
|
RulesetID = 0,
|
||||||
Mods = user.Mods,
|
Mods = user.Mods,
|
||||||
MaximumScoringValues = new ScoringValues
|
MaximumStatistics = new Dictionary<HitResult, int>
|
||||||
{
|
{
|
||||||
BaseScore = 10000,
|
{ HitResult.Perfect, 100 }
|
||||||
MaxCombo = 1000,
|
|
||||||
CountBasicHitObjects = 1000
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ 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.MaximumScoringValues = state.ScoreProcessor.MaximumScoringValues;
|
currentState.MaximumStatistics = state.ScoreProcessor.MaximumStatistics;
|
||||||
|
|
||||||
currentBeatmap = state.Beatmap;
|
currentBeatmap = state.Beatmap;
|
||||||
currentScore = score;
|
currentScore = score;
|
||||||
|
@ -152,12 +152,12 @@ namespace osu.Game.Online.Spectator
|
|||||||
|
|
||||||
scoreInfo.MaxCombo = frame.Header.MaxCombo;
|
scoreInfo.MaxCombo = frame.Header.MaxCombo;
|
||||||
scoreInfo.Statistics = frame.Header.Statistics;
|
scoreInfo.Statistics = frame.Header.Statistics;
|
||||||
|
scoreInfo.MaximumStatistics = spectatorState.MaximumStatistics;
|
||||||
|
|
||||||
Accuracy.Value = frame.Header.Accuracy;
|
Accuracy.Value = frame.Header.Accuracy;
|
||||||
Combo.Value = frame.Header.Combo;
|
Combo.Value = frame.Header.Combo;
|
||||||
|
|
||||||
scoreProcessor.ExtractScoringValues(frame.Header, out var currentScoringValues, out _);
|
TotalScore.Value = scoreProcessor.ComputeScore(Mode.Value, scoreInfo);
|
||||||
TotalScore.Value = scoreProcessor.ComputeScore(Mode.Value, currentScoringValues, spectatorState.MaximumScoringValues);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -9,7 +9,7 @@ using System.Diagnostics.CodeAnalysis;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MessagePack;
|
using MessagePack;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
|
||||||
namespace osu.Game.Online.Spectator
|
namespace osu.Game.Online.Spectator
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ namespace osu.Game.Online.Spectator
|
|||||||
public SpectatedUserState State { get; set; }
|
public SpectatedUserState State { get; set; }
|
||||||
|
|
||||||
[Key(4)]
|
[Key(4)]
|
||||||
public ScoringValues MaximumScoringValues { get; set; }
|
public Dictionary<HitResult, int> MaximumStatistics { get; set; } = new Dictionary<HitResult, int>();
|
||||||
|
|
||||||
public bool Equals(SpectatorState other)
|
public bool Equals(SpectatorState other)
|
||||||
{
|
{
|
||||||
|
@ -10,7 +10,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Online.Spectator;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
@ -90,17 +89,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
private readonly double accuracyPortion;
|
private readonly double accuracyPortion;
|
||||||
private readonly double comboPortion;
|
private readonly double comboPortion;
|
||||||
|
|
||||||
/// <summary>
|
public Dictionary<HitResult, int> MaximumStatistics
|
||||||
/// Scoring values for a perfect play.
|
|
||||||
/// </summary>
|
|
||||||
public ScoringValues MaximumScoringValues
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!beatmapApplied)
|
if (!beatmapApplied)
|
||||||
throw new InvalidOperationException($"Cannot access maximum scoring values before calling {nameof(ApplyBeatmap)}.");
|
throw new InvalidOperationException($"Cannot access maximum statistics before calling {nameof(ApplyBeatmap)}.");
|
||||||
|
|
||||||
return maximumScoringValues;
|
return new Dictionary<HitResult, int>(maximumResultCounts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +264,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
private void updateScore()
|
private void updateScore()
|
||||||
{
|
{
|
||||||
Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1;
|
Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1;
|
||||||
TotalScore.Value = ComputeScore(Mode.Value, currentScoringValues, maximumScoringValues);
|
TotalScore.Value = computeScore(Mode.Value, currentScoringValues, maximumScoringValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -303,9 +299,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
||||||
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
||||||
|
|
||||||
ExtractScoringValues(scoreInfo, out var current, out var maximum);
|
extractScoringValues(scoreInfo, out var current, out var maximum);
|
||||||
|
|
||||||
return ComputeScore(mode, current, maximum);
|
return computeScore(mode, current, maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -316,7 +312,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <param name="maximum">The maximum scoring values.</param>
|
/// <param name="maximum">The maximum scoring values.</param>
|
||||||
/// <returns>The total score computed from the given scoring values.</returns>
|
/// <returns>The total score computed from the given scoring values.</returns>
|
||||||
[Pure]
|
[Pure]
|
||||||
public long ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum)
|
private long computeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum)
|
||||||
{
|
{
|
||||||
double accuracyRatio = maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1;
|
double accuracyRatio = maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1;
|
||||||
double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1;
|
double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1;
|
||||||
@ -474,14 +470,14 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// Consumers are expected to more accurately fill in the above values through external means.
|
/// Consumers are expected to more accurately fill in the above values through external means.
|
||||||
/// <para>
|
/// <para>
|
||||||
/// <b>Ensure</b> to fill in the maximum <see cref="ScoringValues.CountBasicHitObjects"/> for use in
|
/// <b>Ensure</b> to fill in the maximum <see cref="ScoringValues.CountBasicHitObjects"/> for use in
|
||||||
/// <see cref="ComputeScore(osu.Game.Rulesets.Scoring.ScoringMode,osu.Game.Scoring.ScoringValues,osu.Game.Scoring.ScoringValues)"/>.
|
/// <see cref="computeScore(osu.Game.Rulesets.Scoring.ScoringMode,ScoringValues,ScoringValues)"/>.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="scoreInfo">The score to extract scoring values from.</param>
|
/// <param name="scoreInfo">The score to extract scoring values from.</param>
|
||||||
/// <param name="current">The "current" scoring values, representing the hit statistics as they appear.</param>
|
/// <param name="current">The "current" scoring values, representing the hit statistics as they appear.</param>
|
||||||
/// <param name="maximum">The "maximum" scoring values, representing the hit statistics as if the maximum hit result was attained each time.</param>
|
/// <param name="maximum">The "maximum" scoring values, representing the hit statistics as if the maximum hit result was attained each time.</param>
|
||||||
[Pure]
|
[Pure]
|
||||||
internal void ExtractScoringValues(ScoreInfo scoreInfo, out ScoringValues current, out ScoringValues maximum)
|
private void extractScoringValues(ScoreInfo scoreInfo, out ScoringValues current, out ScoringValues maximum)
|
||||||
{
|
{
|
||||||
extractScoringValues(scoreInfo.Statistics, out current, out maximum);
|
extractScoringValues(scoreInfo.Statistics, out current, out maximum);
|
||||||
current.MaxCombo = scoreInfo.MaxCombo;
|
current.MaxCombo = scoreInfo.MaxCombo;
|
||||||
@ -490,31 +486,6 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
extractScoringValues(scoreInfo.MaximumStatistics, out _, out maximum);
|
extractScoringValues(scoreInfo.MaximumStatistics, out _, out maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Applies a best-effort extraction of hit statistics into <see cref="ScoringValues"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This method is useful in a variety of situations, with a few drawbacks that need to be considered:
|
|
||||||
/// <list type="bullet">
|
|
||||||
/// <item>The maximum <see cref="ScoringValues.BonusScore"/> will always be 0.</item>
|
|
||||||
/// <item>The current and maximum <see cref="ScoringValues.CountBasicHitObjects"/> will always be the same value.</item>
|
|
||||||
/// </list>
|
|
||||||
/// Consumers are expected to more accurately fill in the above values through external means.
|
|
||||||
/// <para>
|
|
||||||
/// <b>Ensure</b> to fill in the maximum <see cref="ScoringValues.CountBasicHitObjects"/> for use in
|
|
||||||
/// <see cref="ComputeScore(osu.Game.Rulesets.Scoring.ScoringMode,osu.Game.Scoring.ScoringValues,osu.Game.Scoring.ScoringValues)"/>.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="header">The replay frame header to extract scoring values from.</param>
|
|
||||||
/// <param name="current">The "current" scoring values, representing the hit statistics as they appear.</param>
|
|
||||||
/// <param name="maximum">The "maximum" scoring values, representing the hit statistics as if the maximum hit result was attained each time.</param>
|
|
||||||
[Pure]
|
|
||||||
internal void ExtractScoringValues(FrameHeader header, out ScoringValues current, out ScoringValues maximum)
|
|
||||||
{
|
|
||||||
extractScoringValues(header.Statistics, out current, out maximum);
|
|
||||||
current.MaxCombo = header.MaxCombo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies a best-effort extraction of hit statistics into <see cref="ScoringValues"/>.
|
/// Applies a best-effort extraction of hit statistics into <see cref="ScoringValues"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -589,6 +560,32 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
hitEvents.Clear();
|
hitEvents.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the required scoring data that fulfils the minimum requirements for a <see cref="ScoreProcessor"/> to calculate score.
|
||||||
|
/// </summary>
|
||||||
|
private struct ScoringValues
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The sum of all "basic" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBasic"/> and <see cref="Judgement.ToNumericResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
public long BaseScore;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sum of all "bonus" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBonus"/> and <see cref="Judgement.ToNumericResult"/>.
|
||||||
|
/// </summary>
|
||||||
|
public long BonusScore;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The highest achieved combo.
|
||||||
|
/// </summary>
|
||||||
|
public int MaxCombo;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The count of "basic" <see cref="HitObject"/>s. See: <see cref="HitResultExtensions.IsBasic"/>.
|
||||||
|
/// </summary>
|
||||||
|
public int CountBasicHitObjects;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ScoringMode
|
public enum ScoringMode
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
// 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 disable
|
|
||||||
|
|
||||||
using MessagePack;
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
|
|
||||||
namespace osu.Game.Scoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Stores the required scoring data that fulfils the minimum requirements for a <see cref="ScoreProcessor"/> to calculate score.
|
|
||||||
/// </summary>
|
|
||||||
[MessagePackObject]
|
|
||||||
public struct ScoringValues
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The sum of all "basic" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBasic"/> and <see cref="Judgement.ToNumericResult"/>.
|
|
||||||
/// </summary>
|
|
||||||
[Key(0)]
|
|
||||||
public long BaseScore;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The sum of all "bonus" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBonus"/> and <see cref="Judgement.ToNumericResult"/>.
|
|
||||||
/// </summary>
|
|
||||||
[Key(1)]
|
|
||||||
public long BonusScore;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The highest achieved combo.
|
|
||||||
/// </summary>
|
|
||||||
[Key(2)]
|
|
||||||
public int MaxCombo;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The count of "basic" <see cref="HitObject"/>s. See: <see cref="HitResultExtensions.IsBasic"/>.
|
|
||||||
/// </summary>
|
|
||||||
[Key(3)]
|
|
||||||
public int CountBasicHitObjects;
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user