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:
parent
d74bf2a096
commit
6c6f8621c1
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user