1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 09:27:29 +08:00

Add score processor statistics to replay header

This commit is contained in:
Dan Balasescu 2023-05-19 16:25:52 +09:00
parent d74bf2a096
commit 6c6f8621c1
6 changed files with 83 additions and 24 deletions

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
@ -79,5 +80,21 @@ namespace osu.Game.Rulesets.Catch.Scoring
hitTinyDroplets = 0;
currentBasicJudgements = 0;
}
public override void WriteScoreProcessorStatistics(IDictionary<string, object> statistics)
{
base.WriteScoreProcessorStatistics(statistics);
statistics.Add(nameof(hitTinyDroplets), hitTinyDroplets);
statistics.Add(nameof(currentBasicJudgements), currentBasicJudgements);
}
public override void ReadScoreProcessorStatistics(IReadOnlyDictionary<string, object> statistics)
{
base.ReadScoreProcessorStatistics(statistics);
hitTinyDroplets = (int)statistics.GetValueOrDefault(nameof(hitTinyDroplets), 0);
currentBasicJudgements = (int)statistics.GetValueOrDefault(nameof(currentBasicJudgements), 0);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using MessagePack;
using Newtonsoft.Json;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Online.Spectator
@ -20,10 +21,10 @@ namespace osu.Game.Online.Spectator
[Key(1)]
public IList<LegacyReplayFrame> Frames { get; set; }
public FrameDataBundle(ScoreInfo score, IList<LegacyReplayFrame> frames)
public FrameDataBundle(ScoreInfo score, ScoreProcessor scoreProcessor, IList<LegacyReplayFrame> frames)
{
Frames = frames;
Header = new FrameHeader(score);
Header = new FrameHeader(score, scoreProcessor);
}
[JsonConstructor]

View File

@ -15,66 +15,77 @@ namespace osu.Game.Online.Spectator
public class FrameHeader
{
/// <summary>
/// The current accuracy of the score.
/// The total score.
/// </summary>
[Key(0)]
public long TotalScore { get; set; }
/// <summary>
/// The current accuracy of the score.
/// </summary>
[Key(1)]
public double Accuracy { get; set; }
/// <summary>
/// The current combo of the score.
/// </summary>
[Key(1)]
[Key(2)]
public int Combo { get; set; }
/// <summary>
/// The maximum combo achieved up to the current point in time.
/// </summary>
[Key(2)]
[Key(3)]
public int MaxCombo { get; set; }
/// <summary>
/// Cumulative hit statistics.
/// </summary>
[Key(3)]
[Key(4)]
public Dictionary<HitResult, int> Statistics { get; set; }
/// <summary>
/// Additional statistics that guides the score processor to calculate the correct score for this frame.
/// </summary>
[Key(5)]
public Dictionary<string, object> ScoreProcessorStatistics { get; set; }
/// <summary>
/// The time at which this frame was received by the server.
/// </summary>
[Key(4)]
[Key(6)]
public DateTimeOffset ReceivedTime { get; set; }
/// <summary>
/// The total score.
/// </summary>
[Key(5)]
public long TotalScore { get; set; }
/// <summary>
/// Construct header summary information from a point-in-time reference to a score which is actively being played.
/// </summary>
/// <param name="score">The score for reference.</param>
public FrameHeader(ScoreInfo score)
/// <param name="scoreProcessor">The score processor for reference.</param>
public FrameHeader(ScoreInfo score, ScoreProcessor scoreProcessor)
{
TotalScore = score.TotalScore;
Accuracy = score.Accuracy;
Combo = score.Combo;
MaxCombo = score.MaxCombo;
Accuracy = score.Accuracy;
TotalScore = score.TotalScore;
// copy for safety
Statistics = new Dictionary<HitResult, int>(score.Statistics);
ScoreProcessorStatistics = new Dictionary<string, object>();
scoreProcessor.WriteScoreProcessorStatistics(ScoreProcessorStatistics);
}
[JsonConstructor]
[SerializationConstructor]
public FrameHeader(double accuracy, int combo, int maxCombo, Dictionary<HitResult, int> statistics, DateTimeOffset receivedTime, long totalScore)
public FrameHeader(long totalScore, double accuracy, int combo, int maxCombo, Dictionary<HitResult, int> statistics, Dictionary<string, object> scoreProcessorStatistics, DateTimeOffset receivedTime)
{
TotalScore = totalScore;
Accuracy = accuracy;
Combo = combo;
MaxCombo = maxCombo;
Accuracy = accuracy;
Statistics = statistics;
ScoreProcessorStatistics = scoreProcessorStatistics;
ReceivedTime = receivedTime;
TotalScore = totalScore;
}
}
}

View File

@ -16,6 +16,7 @@ using osu.Game.Online.API;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Replays.Types;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play;
@ -82,6 +83,7 @@ namespace osu.Game.Online.Spectator
private IBeatmap? currentBeatmap;
private Score? currentScore;
private long? currentScoreToken;
private ScoreProcessor? currentScoreProcessor;
private readonly Queue<FrameDataBundle> pendingFrameBundles = new Queue<FrameDataBundle>();
@ -192,6 +194,7 @@ namespace osu.Game.Online.Spectator
currentBeatmap = state.Beatmap;
currentScore = score;
currentScoreToken = scoreToken;
currentScoreProcessor = state.ScoreProcessor;
BeginPlayingInternal(currentScoreToken, currentState);
});
@ -302,9 +305,10 @@ namespace osu.Game.Online.Spectator
return;
Debug.Assert(currentScore != null);
Debug.Assert(currentScoreProcessor != null);
var frames = pendingFrames.ToArray();
var bundle = new FrameDataBundle(currentScore.ScoreInfo, frames);
var bundle = new FrameDataBundle(currentScore.ScoreInfo, currentScoreProcessor, frames);
pendingFrames.Clear();
lastPurgeTime = Time.Current;

View File

@ -394,19 +394,34 @@ namespace osu.Game.Rulesets.Scoring
Combo.Value = frame.Header.Combo;
HighestCombo.Value = frame.Header.MaxCombo;
TotalScore.Value = frame.Header.TotalScore;
scoreResultCounts.Clear();
scoreResultCounts.AddRange(frame.Header.Statistics);
ReadScoreProcessorStatistics(frame.Header.ScoreProcessorStatistics);
updateScore();
OnResetFromReplayFrame?.Invoke();
}
protected override void Dispose(bool isDisposing)
public virtual void WriteScoreProcessorStatistics(IDictionary<string, object> statistics)
{
base.Dispose(isDisposing);
hitEvents.Clear();
statistics.Add(nameof(currentMaximumBaseScore), currentMaximumBaseScore);
statistics.Add(nameof(currentBaseScore), currentBaseScore);
statistics.Add(nameof(currentCountBasicJudgements), currentCountBasicJudgements);
statistics.Add(nameof(currentComboPortion), currentComboPortion);
statistics.Add(nameof(currentBonusPortion), currentBonusPortion);
}
public virtual void ReadScoreProcessorStatistics(IReadOnlyDictionary<string, object> statistics)
{
currentMaximumBaseScore = (double)statistics.GetValueOrDefault(nameof(currentMaximumBaseScore), 0);
currentBaseScore = (double)statistics.GetValueOrDefault(nameof(currentBaseScore), 0);
currentCountBasicJudgements = (int)statistics.GetValueOrDefault(nameof(currentCountBasicJudgements), 0);
currentComboPortion = (double)statistics.GetValueOrDefault(nameof(currentComboPortion), 0);
currentBonusPortion = (double)statistics.GetValueOrDefault(nameof(currentBonusPortion), 0);
}
#region Static helper methods
@ -464,6 +479,12 @@ namespace osu.Game.Rulesets.Scoring
}
#endregion
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
hitEvents.Clear();
}
}
public enum ScoringMode

View File

@ -12,7 +12,9 @@ using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.Spectator;
using osu.Game.Replays.Legacy;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
namespace osu.Game.Tests.Visual.Spectator
@ -44,6 +46,9 @@ namespace osu.Game.Tests.Visual.Spectator
[Resolved]
private IAPIProvider api { get; set; } = null!;
[Resolved]
private RulesetStore rulesetStore { get; set; } = null!;
public TestSpectatorClient()
{
OnNewFrames += (i, bundle) => lastReceivedUserFrames[i] = bundle.Frames[^1];
@ -119,7 +124,7 @@ namespace osu.Game.Tests.Visual.Spectator
if (frames.Count == 0)
return;
var bundle = new FrameDataBundle(new ScoreInfo { Combo = currentFrameIndex }, frames.ToArray());
var bundle = new FrameDataBundle(new ScoreInfo { Combo = currentFrameIndex }, new ScoreProcessor(rulesetStore.GetRuleset(0)!.CreateInstance()), frames.ToArray());
((ISpectatorClient)this).UserSentFrames(userId, bundle);
frames.Clear();