mirror of
https://github.com/osukey/osukey.git
synced 2025-08-05 15:44:04 +09:00
Merge branch 'master' into osu-diff-calc-max-combo
This commit is contained in:
@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
public Mod[] Mods { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The combined star rating of all skill.
|
||||
/// The combined star rating of all skills.
|
||||
/// </summary>
|
||||
[JsonProperty("star_rating", Order = -3)]
|
||||
public double StarRating { get; set; }
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Game.Rulesets.Difficulty
|
||||
@ -12,5 +13,15 @@ namespace osu.Game.Rulesets.Difficulty
|
||||
/// </summary>
|
||||
[JsonProperty("pp")]
|
||||
public double Total { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="PerformanceDisplayAttribute"/> for each attribute so that a performance breakdown can be displayed.
|
||||
/// Some attributes may be omitted if they are not meant for display.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||
{
|
||||
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
21
osu.Game/Rulesets/Difficulty/PerformanceBreakdown.cs
Normal file
21
osu.Game/Rulesets/Difficulty/PerformanceBreakdown.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for generating a performance breakdown by comparing performance to a perfect play.
|
||||
/// </summary>
|
||||
public class PerformanceBreakdown
|
||||
{
|
||||
/// <summary>
|
||||
/// Actual gameplay performance.
|
||||
/// </summary>
|
||||
public PerformanceAttributes Performance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Performance of a perfect play for comparison.
|
||||
/// </summary>
|
||||
public PerformanceAttributes PerfectPerformance { get; set; }
|
||||
}
|
||||
}
|
105
osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs
Normal file
105
osu.Game/Rulesets/Difficulty/PerformanceBreakdownCalculator.cs
Normal file
@ -0,0 +1,105 @@
|
||||
// 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.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
public class PerformanceBreakdownCalculator
|
||||
{
|
||||
private readonly IBeatmap playableBeatmap;
|
||||
private readonly BeatmapDifficultyCache difficultyCache;
|
||||
private readonly ScorePerformanceCache performanceCache;
|
||||
|
||||
public PerformanceBreakdownCalculator(IBeatmap playableBeatmap, BeatmapDifficultyCache difficultyCache, ScorePerformanceCache performanceCache)
|
||||
{
|
||||
this.playableBeatmap = playableBeatmap;
|
||||
this.difficultyCache = difficultyCache;
|
||||
this.performanceCache = performanceCache;
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
public async Task<PerformanceBreakdown> CalculateAsync(ScoreInfo score, CancellationToken cancellationToken = default)
|
||||
{
|
||||
PerformanceAttributes[] performanceArray = await Task.WhenAll(
|
||||
// compute actual performance
|
||||
performanceCache.CalculatePerformanceAsync(score, cancellationToken),
|
||||
// compute performance for perfect play
|
||||
getPerfectPerformance(score, cancellationToken)
|
||||
).ConfigureAwait(false);
|
||||
|
||||
return new PerformanceBreakdown { Performance = performanceArray[0], PerfectPerformance = performanceArray[1] };
|
||||
}
|
||||
|
||||
[ItemCanBeNull]
|
||||
private Task<PerformanceAttributes> getPerfectPerformance(ScoreInfo score, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(async () =>
|
||||
{
|
||||
Ruleset ruleset = score.Ruleset.CreateInstance();
|
||||
ScoreInfo perfectPlay = score.DeepClone();
|
||||
perfectPlay.Accuracy = 1;
|
||||
perfectPlay.Passed = true;
|
||||
|
||||
// calculate max combo
|
||||
// todo: Get max combo from difficulty calculator instead when diffcalc properly supports lazer-first scores
|
||||
perfectPlay.MaxCombo = calculateMaxCombo(playableBeatmap);
|
||||
|
||||
// create statistics assuming all hit objects have perfect hit result
|
||||
var statistics = playableBeatmap.HitObjects
|
||||
.SelectMany(getPerfectHitResults)
|
||||
.GroupBy(hr => hr, (hr, list) => (hitResult: hr, count: list.Count()))
|
||||
.ToDictionary(pair => pair.hitResult, pair => pair.count);
|
||||
perfectPlay.Statistics = statistics;
|
||||
|
||||
// calculate total score
|
||||
ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor();
|
||||
scoreProcessor.HighestCombo.Value = perfectPlay.MaxCombo;
|
||||
scoreProcessor.Mods.Value = perfectPlay.Mods;
|
||||
perfectPlay.TotalScore = (long)scoreProcessor.GetImmediateScore(ScoringMode.Standardised, perfectPlay.MaxCombo, statistics);
|
||||
|
||||
// compute rank achieved
|
||||
// default to SS, then adjust the rank with mods
|
||||
perfectPlay.Rank = ScoreRank.X;
|
||||
|
||||
foreach (IApplicableToScoreProcessor mod in perfectPlay.Mods.OfType<IApplicableToScoreProcessor>())
|
||||
{
|
||||
perfectPlay.Rank = mod.AdjustRank(perfectPlay.Rank, 1);
|
||||
}
|
||||
|
||||
// calculate performance for this perfect score
|
||||
var difficulty = await difficultyCache.GetDifficultyAsync(
|
||||
playableBeatmap.BeatmapInfo,
|
||||
score.Ruleset,
|
||||
score.Mods,
|
||||
cancellationToken
|
||||
).ConfigureAwait(false);
|
||||
|
||||
// ScorePerformanceCache is not used to avoid caching multiple copies of essentially identical perfect performance attributes
|
||||
return difficulty == null ? null : ruleset.CreatePerformanceCalculator(difficulty.Value.Attributes, perfectPlay)?.Calculate();
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
private int calculateMaxCombo(IBeatmap beatmap)
|
||||
{
|
||||
return beatmap.HitObjects.SelectMany(getPerfectHitResults).Count(r => r.AffectsCombo());
|
||||
}
|
||||
|
||||
private IEnumerable<HitResult> getPerfectHitResults(HitObject hitObject)
|
||||
{
|
||||
foreach (HitObject nested in hitObject.NestedHitObjects)
|
||||
yield return nested.CreateJudgement().MaxResult;
|
||||
|
||||
yield return hitObject.CreateJudgement().MaxResult;
|
||||
}
|
||||
}
|
||||
}
|
33
osu.Game/Rulesets/Difficulty/PerformanceDisplayAttribute.cs
Normal file
33
osu.Game/Rulesets/Difficulty/PerformanceDisplayAttribute.cs
Normal file
@ -0,0 +1,33 @@
|
||||
// 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.
|
||||
|
||||
namespace osu.Game.Rulesets.Difficulty
|
||||
{
|
||||
/// <summary>
|
||||
/// Data for displaying a performance attribute to user. Includes a display name for clarity.
|
||||
/// </summary>
|
||||
public class PerformanceDisplayAttribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the attribute property in <see cref="PerformanceAttributes"/>.
|
||||
/// </summary>
|
||||
public string PropertyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A custom display name for the attribute.
|
||||
/// </summary>
|
||||
public string DisplayName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The associated attribute value.
|
||||
/// </summary>
|
||||
public double Value { get; }
|
||||
|
||||
public PerformanceDisplayAttribute(string propertyName, string displayName, double value)
|
||||
{
|
||||
PropertyName = propertyName;
|
||||
DisplayName = displayName;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user