mirror of
https://github.com/ppy/osu.git
synced 2024-12-05 09:42:54 +08:00
Compare commits
21 Commits
b047c8ab0a
...
22a28c1447
Author | SHA1 | Date | |
---|---|---|---|
|
22a28c1447 | ||
|
f09d8f097a | ||
|
457957d3b8 | ||
|
2ceb3f6f85 | ||
|
d6e5a47e52 | ||
|
808d44d2a6 | ||
|
d12fd89f44 | ||
|
d75eb3a88a | ||
|
26e9c21d9a | ||
|
5a989ecdd8 | ||
|
aa5dba67e0 | ||
|
b7ae1521cc | ||
|
11cb9e72f5 | ||
|
c5d5a5b342 | ||
|
109a5ad3d7 | ||
|
4114ff5cf0 | ||
|
d7ae4a0775 | ||
|
ae25f27785 | ||
|
6e2f8cf4c2 | ||
|
e88dff0c87 | ||
|
e70f257947 |
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.EmptyFreeform
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
return new DifficultyAttributes(mods, 0);
|
return new DifficultyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||||
|
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
return new DifficultyAttributes(mods, 0);
|
return new DifficultyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||||
|
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.EmptyScrolling
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
return new DifficultyAttributes(mods, 0);
|
return new DifficultyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||||
|
@ -19,9 +19,9 @@ namespace osu.Game.Rulesets.Pippidon
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
return new DifficultyAttributes(mods, 0);
|
return new DifficultyAttributes();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) => Enumerable.Empty<DifficultyHitObject>();
|
||||||
|
96
osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs
Normal file
96
osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// 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.IO;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Formats;
|
||||||
|
using osu.Game.IO;
|
||||||
|
using osu.Game.IO.Archives;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
using osu.Game.Rulesets.Mania;
|
||||||
|
using osu.Game.Rulesets.Osu;
|
||||||
|
using osu.Game.Rulesets.Taiko;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
|
namespace osu.Game.Benchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkDifficultyCalculation : BenchmarkTest
|
||||||
|
{
|
||||||
|
private FlatWorkingBeatmap beatmap = null!;
|
||||||
|
|
||||||
|
private IDifficultyAttributes osuAttributes = null!;
|
||||||
|
private IDifficultyAttributes taikoAttributes = null!;
|
||||||
|
private IDifficultyAttributes catchAttributes = null!;
|
||||||
|
private IDifficultyAttributes maniaAttributes = null!;
|
||||||
|
|
||||||
|
public override void SetUp()
|
||||||
|
{
|
||||||
|
using var resources = new DllResourceStore(typeof(TestResources).Assembly);
|
||||||
|
using var archive = resources.GetStream("Resources/Archives/241526 Soleily - Renatus.osz");
|
||||||
|
using var zipReader = new ZipArchiveReader(archive);
|
||||||
|
|
||||||
|
using var beatmapStream = new MemoryStream();
|
||||||
|
zipReader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream);
|
||||||
|
beatmapStream.Seek(0, SeekOrigin.Begin);
|
||||||
|
var reader = new LineBufferedReader(beatmapStream);
|
||||||
|
var decoder = Decoder.GetDecoder<Beatmap>(reader);
|
||||||
|
|
||||||
|
beatmap = new FlatWorkingBeatmap(decoder.Decode(reader));
|
||||||
|
|
||||||
|
// Prepare difficulty attributes for an isolated performance calculation in every mode.
|
||||||
|
osuAttributes = DifficultyOsu();
|
||||||
|
taikoAttributes = DifficultyTaiko();
|
||||||
|
catchAttributes = DifficultyCatch();
|
||||||
|
maniaAttributes = DifficultyMania();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IDifficultyAttributes DifficultyOsu() => new OsuRuleset().CreateDifficultyCalculator(beatmap).Calculate();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IDifficultyAttributes DifficultyTaiko() => new TaikoRuleset().CreateDifficultyCalculator(beatmap).Calculate();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IDifficultyAttributes DifficultyCatch() => new CatchRuleset().CreateDifficultyCalculator(beatmap).Calculate();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IDifficultyAttributes DifficultyMania() => new ManiaRuleset().CreateDifficultyCalculator(beatmap).Calculate();
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void PerformanceOsu()
|
||||||
|
{
|
||||||
|
Ruleset ruleset = new OsuRuleset();
|
||||||
|
ScoreInfo score = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo);
|
||||||
|
ruleset.CreatePerformanceCalculator()!.Calculate(score, osuAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void PerformanceTaiko()
|
||||||
|
{
|
||||||
|
Ruleset ruleset = new TaikoRuleset();
|
||||||
|
ScoreInfo score = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo);
|
||||||
|
ruleset.CreatePerformanceCalculator()!.Calculate(score, taikoAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void PerformanceCatch()
|
||||||
|
{
|
||||||
|
Ruleset ruleset = new CatchRuleset();
|
||||||
|
ScoreInfo score = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo);
|
||||||
|
ruleset.CreatePerformanceCalculator()!.Calculate(score, catchAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void PerformanceMania()
|
||||||
|
{
|
||||||
|
Ruleset ruleset = new ManiaRuleset();
|
||||||
|
ScoreInfo score = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo);
|
||||||
|
ruleset.CreatePerformanceCalculator()!.Calculate(score, maniaAttributes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,15 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||||
{
|
{
|
||||||
public class CatchDifficultyAttributes : DifficultyAttributes
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public struct CatchDifficultyAttributes : IDifficultyAttributes
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
|
/// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -19,22 +26,19 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
[JsonProperty("approach_rate")]
|
[JsonProperty("approach_rate")]
|
||||||
public double ApproachRate { get; set; }
|
public double ApproachRate { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
{
|
{
|
||||||
foreach (var v in base.ToDatabaseAttributes())
|
yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return v;
|
|
||||||
|
|
||||||
// Todo: osu!catch should not output star rating in the 'aim' attribute.
|
// Todo: osu!catch should not output star rating in the 'aim' attribute.
|
||||||
yield return (ATTRIB_ID_AIM, StarRating);
|
yield return (IDifficultyAttributes.ATTRIB_ID_AIM, StarRating);
|
||||||
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
yield return (IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values, onlineInfo);
|
MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[IDifficultyAttributes.ATTRIB_ID_AIM];
|
||||||
StarRating = values[ATTRIB_ID_AIM];
|
ApproachRate = values[IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE];
|
||||||
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
return new CatchDifficultyAttributes { Mods = mods };
|
return new CatchDifficultyAttributes();
|
||||||
|
|
||||||
// this is the same as osu!, so there's potential to share the implementation... maybe
|
// this is the same as osu!, so there's potential to share the implementation... maybe
|
||||||
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
|
double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate;
|
||||||
@ -41,7 +41,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
CatchDifficultyAttributes attributes = new CatchDifficultyAttributes
|
CatchDifficultyAttributes attributes = new CatchDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier,
|
StarRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier,
|
||||||
Mods = mods,
|
|
||||||
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
|
ApproachRate = preempt > 1200.0 ? -(preempt - 1800.0) / 120.0 : -(preempt - 1200.0) / 150.0 + 5.0,
|
||||||
MaxCombo = beatmap.GetMaxCombo(),
|
MaxCombo = beatmap.GetMaxCombo(),
|
||||||
};
|
};
|
||||||
|
@ -1,11 +1,23 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Catch.Difficulty
|
namespace osu.Game.Rulesets.Catch.Difficulty
|
||||||
{
|
{
|
||||||
public class CatchPerformanceAttributes : PerformanceAttributes
|
public struct CatchPerformanceAttributes : IPerformanceAttributes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated score performance points.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pp")]
|
||||||
|
public double Total { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||||
|
{
|
||||||
|
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes)
|
protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
{
|
{
|
||||||
var catchAttributes = (CatchDifficultyAttributes)attributes;
|
var catchAttributes = (CatchDifficultyAttributes)attributes;
|
||||||
|
|
||||||
|
@ -8,8 +8,15 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
{
|
{
|
||||||
public class ManiaDifficultyAttributes : DifficultyAttributes
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public struct ManiaDifficultyAttributes : IDifficultyAttributes
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc).
|
/// The hit window for a GREAT hit inclusive of rate-adjusting mods (DT/HT/etc).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -19,21 +26,18 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
[JsonProperty("great_hit_window")]
|
[JsonProperty("great_hit_window")]
|
||||||
public double GreatHitWindow { get; set; }
|
public double GreatHitWindow { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
{
|
{
|
||||||
foreach (var v in base.ToDatabaseAttributes())
|
yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return v;
|
yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
|
yield return (IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
|
||||||
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values, onlineInfo);
|
MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY];
|
||||||
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
GreatHitWindow = values[IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,10 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
originalOverallDifficulty = beatmap.BeatmapInfo.Difficulty.OverallDifficulty;
|
originalOverallDifficulty = beatmap.BeatmapInfo.Difficulty.OverallDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
return new ManiaDifficultyAttributes { Mods = mods };
|
return new ManiaDifficultyAttributes();
|
||||||
|
|
||||||
HitWindows hitWindows = new ManiaHitWindows();
|
HitWindows hitWindows = new ManiaHitWindows();
|
||||||
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
|
hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty);
|
||||||
@ -49,7 +49,6 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
ManiaDifficultyAttributes attributes = new ManiaDifficultyAttributes
|
ManiaDifficultyAttributes attributes = new ManiaDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = skills[0].DifficultyValue() * difficulty_multiplier,
|
StarRating = skills[0].DifficultyValue() * difficulty_multiplier,
|
||||||
Mods = mods,
|
|
||||||
// In osu-stable mania, rate-adjustment mods don't affect the hit window.
|
// In osu-stable mania, rate-adjustment mods don't affect the hit window.
|
||||||
// This is done the way it is to introduce fractional differences in order to match osu-stable for the time being.
|
// This is done the way it is to introduce fractional differences in order to match osu-stable for the time being.
|
||||||
GreatHitWindow = Math.Ceiling((int)(getHitWindow300(mods) * clockRate) / clockRate),
|
GreatHitWindow = Math.Ceiling((int)(getHitWindow300(mods) * clockRate) / clockRate),
|
||||||
|
@ -7,16 +7,20 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Mania.Difficulty
|
namespace osu.Game.Rulesets.Mania.Difficulty
|
||||||
{
|
{
|
||||||
public class ManiaPerformanceAttributes : PerformanceAttributes
|
public struct ManiaPerformanceAttributes : IPerformanceAttributes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated score performance points.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pp")]
|
||||||
|
public double Total { get; set; }
|
||||||
|
|
||||||
[JsonProperty("difficulty")]
|
[JsonProperty("difficulty")]
|
||||||
public double Difficulty { get; set; }
|
public double Difficulty { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||||
{
|
{
|
||||||
foreach (var attribute in base.GetAttributesForDisplay())
|
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||||
yield return attribute;
|
|
||||||
|
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Difficulty), "Difficulty", Difficulty);
|
yield return new PerformanceDisplayAttribute(nameof(Difficulty), "Difficulty", Difficulty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Mania.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes)
|
protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
{
|
{
|
||||||
var maniaAttributes = (ManiaDifficultyAttributes)attributes;
|
var maniaAttributes = (ManiaDifficultyAttributes)attributes;
|
||||||
|
|
||||||
|
@ -34,6 +34,18 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
|
public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name)
|
||||||
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
|
=> Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic());
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestFlashlightDifficultyNullability()
|
||||||
|
{
|
||||||
|
IWorkingBeatmap beatmap = GetBeatmap("diffcalc-test");
|
||||||
|
|
||||||
|
OsuDifficultyAttributes attributes = (OsuDifficultyAttributes)CreateDifficultyCalculator(beatmap).Calculate();
|
||||||
|
Assert.IsNull(attributes.FlashlightDifficulty);
|
||||||
|
|
||||||
|
attributes = (OsuDifficultyAttributes)CreateDifficultyCalculator(GetBeatmap("diffcalc-test")).Calculate([new OsuModFlashlight()]);
|
||||||
|
Assert.IsNotNull(attributes.FlashlightDifficulty);
|
||||||
|
}
|
||||||
|
|
||||||
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap);
|
protected override DifficultyCalculator CreateDifficultyCalculator(IWorkingBeatmap beatmap) => new OsuDifficultyCalculator(new OsuRuleset().RulesetInfo, beatmap);
|
||||||
|
|
||||||
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
protected override Ruleset CreateRuleset() => new OsuRuleset();
|
||||||
|
@ -2,17 +2,22 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Difficulty;
|
using osu.Game.Rulesets.Difficulty;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Difficulty
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuDifficultyAttributes : DifficultyAttributes
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public struct OsuDifficultyAttributes : IDifficultyAttributes
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The difficulty corresponding to the aim skill.
|
/// The difficulty corresponding to the aim skill.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -33,10 +38,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
public double SpeedNoteCount { get; set; }
|
public double SpeedNoteCount { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The difficulty corresponding to the flashlight skill.
|
/// The difficulty corresponding to the flashlight skill. A null value indicates the non-existence of <see cref="Mods.OsuModFlashlight"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("flashlight_difficulty")]
|
[JsonProperty("flashlight_difficulty")]
|
||||||
public double FlashlightDifficulty { get; set; }
|
public double? FlashlightDifficulty { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes how much of <see cref="AimDifficulty"/> is contributed to by hitcircles or sliders.
|
/// Describes how much of <see cref="AimDifficulty"/> is contributed to by hitcircles or sliders.
|
||||||
@ -90,41 +95,38 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int SpinnerCount { get; set; }
|
public int SpinnerCount { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
{
|
{
|
||||||
foreach (var v in base.ToDatabaseAttributes())
|
yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return v;
|
yield return (IDifficultyAttributes.ATTRIB_ID_AIM, AimDifficulty);
|
||||||
|
yield return (IDifficultyAttributes.ATTRIB_ID_SPEED, SpeedDifficulty);
|
||||||
yield return (ATTRIB_ID_AIM, AimDifficulty);
|
yield return (IDifficultyAttributes.ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
|
||||||
yield return (ATTRIB_ID_SPEED, SpeedDifficulty);
|
yield return (IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
||||||
yield return (ATTRIB_ID_OVERALL_DIFFICULTY, OverallDifficulty);
|
yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
yield return (ATTRIB_ID_APPROACH_RATE, ApproachRate);
|
|
||||||
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
|
||||||
|
|
||||||
if (ShouldSerializeFlashlightDifficulty())
|
if (ShouldSerializeFlashlightDifficulty())
|
||||||
yield return (ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty);
|
yield return (IDifficultyAttributes.ATTRIB_ID_FLASHLIGHT, FlashlightDifficulty!);
|
||||||
|
|
||||||
yield return (ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
|
yield return (IDifficultyAttributes.ATTRIB_ID_SLIDER_FACTOR, SliderFactor);
|
||||||
|
|
||||||
yield return (ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT, AimDifficultStrainCount);
|
yield return (IDifficultyAttributes.ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT, AimDifficultStrainCount);
|
||||||
yield return (ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount);
|
yield return (IDifficultyAttributes.ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount);
|
||||||
yield return (ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount);
|
yield return (IDifficultyAttributes.ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values, onlineInfo);
|
MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO];
|
||||||
|
AimDifficulty = values[IDifficultyAttributes.ATTRIB_ID_AIM];
|
||||||
AimDifficulty = values[ATTRIB_ID_AIM];
|
SpeedDifficulty = values[IDifficultyAttributes.ATTRIB_ID_SPEED];
|
||||||
SpeedDifficulty = values[ATTRIB_ID_SPEED];
|
OverallDifficulty = values[IDifficultyAttributes.ATTRIB_ID_OVERALL_DIFFICULTY];
|
||||||
OverallDifficulty = values[ATTRIB_ID_OVERALL_DIFFICULTY];
|
ApproachRate = values[IDifficultyAttributes.ATTRIB_ID_APPROACH_RATE];
|
||||||
ApproachRate = values[ATTRIB_ID_APPROACH_RATE];
|
StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY];
|
||||||
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
FlashlightDifficulty = values.GetValueOrDefault(IDifficultyAttributes.ATTRIB_ID_FLASHLIGHT);
|
||||||
FlashlightDifficulty = values.GetValueOrDefault(ATTRIB_ID_FLASHLIGHT);
|
SliderFactor = values[IDifficultyAttributes.ATTRIB_ID_SLIDER_FACTOR];
|
||||||
SliderFactor = values[ATTRIB_ID_SLIDER_FACTOR];
|
AimDifficultStrainCount = values[IDifficultyAttributes.ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT];
|
||||||
AimDifficultStrainCount = values[ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT];
|
SpeedDifficultStrainCount = values[IDifficultyAttributes.ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT];
|
||||||
SpeedDifficultStrainCount = values[ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT];
|
SpeedNoteCount = values[IDifficultyAttributes.ATTRIB_ID_SPEED_NOTE_COUNT];
|
||||||
SpeedNoteCount = values[ATTRIB_ID_SPEED_NOTE_COUNT];
|
|
||||||
DrainRate = onlineInfo.DrainRate;
|
DrainRate = onlineInfo.DrainRate;
|
||||||
HitCircleCount = onlineInfo.CircleCount;
|
HitCircleCount = onlineInfo.CircleCount;
|
||||||
SliderCount = onlineInfo.SliderCount;
|
SliderCount = onlineInfo.SliderCount;
|
||||||
@ -138,7 +140,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
// unless the fields are also renamed.
|
// unless the fields are also renamed.
|
||||||
|
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public bool ShouldSerializeFlashlightDifficulty() => Mods.Any(m => m is ModFlashlight);
|
public bool ShouldSerializeFlashlightDifficulty() => FlashlightDifficulty is not null;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -31,17 +31,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
return new OsuDifficultyAttributes { Mods = mods };
|
return new OsuDifficultyAttributes();
|
||||||
|
|
||||||
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
double aimRating = Math.Sqrt(skills[0].DifficultyValue()) * difficulty_multiplier;
|
||||||
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
double aimRatingNoSliders = Math.Sqrt(skills[1].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
double speedRating = Math.Sqrt(skills[2].DifficultyValue()) * difficulty_multiplier;
|
||||||
double speedNotes = ((Speed)skills[2]).RelevantNoteCount();
|
double speedNotes = ((Speed)skills[2]).RelevantNoteCount();
|
||||||
|
|
||||||
double flashlightRating = 0.0;
|
double flashlightRating = 0;
|
||||||
|
|
||||||
if (mods.Any(h => h is OsuModFlashlight))
|
if (mods.Any(h => h is OsuModFlashlight))
|
||||||
flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
|
flashlightRating = Math.Sqrt(skills[3].DifficultyValue()) * difficulty_multiplier;
|
||||||
@ -97,11 +97,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
OsuDifficultyAttributes attributes = new OsuDifficultyAttributes
|
OsuDifficultyAttributes attributes = new OsuDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
Mods = mods,
|
|
||||||
AimDifficulty = aimRating,
|
AimDifficulty = aimRating,
|
||||||
SpeedDifficulty = speedRating,
|
SpeedDifficulty = speedRating,
|
||||||
SpeedNoteCount = speedNotes,
|
SpeedNoteCount = speedNotes,
|
||||||
FlashlightDifficulty = flashlightRating,
|
FlashlightDifficulty = mods.Any(x => x is OsuModFlashlight) ? flashlightRating : null,
|
||||||
SliderFactor = sliderFactor,
|
SliderFactor = sliderFactor,
|
||||||
AimDifficultStrainCount = aimDifficultyStrainCount,
|
AimDifficultStrainCount = aimDifficultyStrainCount,
|
||||||
SpeedDifficultStrainCount = speedDifficultyStrainCount,
|
SpeedDifficultStrainCount = speedDifficultyStrainCount,
|
||||||
|
@ -7,8 +7,14 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Difficulty
|
namespace osu.Game.Rulesets.Osu.Difficulty
|
||||||
{
|
{
|
||||||
public class OsuPerformanceAttributes : PerformanceAttributes
|
public struct OsuPerformanceAttributes : IPerformanceAttributes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated score performance points.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pp")]
|
||||||
|
public double Total { get; set; }
|
||||||
|
|
||||||
[JsonProperty("aim")]
|
[JsonProperty("aim")]
|
||||||
public double Aim { get; set; }
|
public double Aim { get; set; }
|
||||||
|
|
||||||
@ -24,11 +30,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
[JsonProperty("effective_miss_count")]
|
[JsonProperty("effective_miss_count")]
|
||||||
public double EffectiveMissCount { get; set; }
|
public double EffectiveMissCount { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||||
{
|
{
|
||||||
foreach (var attribute in base.GetAttributesForDisplay())
|
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||||
yield return attribute;
|
|
||||||
|
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Aim), "Aim", Aim);
|
yield return new PerformanceDisplayAttribute(nameof(Aim), "Aim", Aim);
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Speed), "Speed", Speed);
|
yield return new PerformanceDisplayAttribute(nameof(Speed), "Speed", Speed);
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy);
|
yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy);
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes)
|
protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
{
|
{
|
||||||
var osuAttributes = (OsuDifficultyAttributes)attributes;
|
var osuAttributes = (OsuDifficultyAttributes)attributes;
|
||||||
|
|
||||||
@ -285,7 +285,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty
|
|||||||
if (!score.Mods.Any(h => h is OsuModFlashlight))
|
if (!score.Mods.Any(h => h is OsuModFlashlight))
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
double flashlightValue = Flashlight.DifficultyToPerformance(attributes.FlashlightDifficulty);
|
double flashlightValue = Flashlight.DifficultyToPerformance(attributes.FlashlightDifficulty!.Value);
|
||||||
|
|
||||||
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
// Penalize misses by assessing # of misses relative to the total # of objects. Default a 3% reduction for any # of misses.
|
||||||
if (effectiveMissCount > 0)
|
if (effectiveMissCount > 0)
|
||||||
|
@ -8,8 +8,15 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
{
|
{
|
||||||
public class TaikoDifficultyAttributes : DifficultyAttributes
|
[JsonObject(MemberSerialization.OptIn)]
|
||||||
|
public struct TaikoDifficultyAttributes : IDifficultyAttributes
|
||||||
{
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The difficulty corresponding to the stamina skill.
|
/// The difficulty corresponding to the stamina skill.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -58,25 +65,22 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
[JsonProperty("ok_hit_window")]
|
[JsonProperty("ok_hit_window")]
|
||||||
public double OkHitWindow { get; set; }
|
public double OkHitWindow { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
{
|
{
|
||||||
foreach (var v in base.ToDatabaseAttributes())
|
yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
yield return v;
|
yield return (IDifficultyAttributes.ATTRIB_ID_DIFFICULTY, StarRating);
|
||||||
|
yield return (IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
||||||
yield return (ATTRIB_ID_DIFFICULTY, StarRating);
|
yield return (IDifficultyAttributes.ATTRIB_ID_OK_HIT_WINDOW, OkHitWindow);
|
||||||
yield return (ATTRIB_ID_GREAT_HIT_WINDOW, GreatHitWindow);
|
yield return (IDifficultyAttributes.ATTRIB_ID_MONO_STAMINA_FACTOR, MonoStaminaFactor);
|
||||||
yield return (ATTRIB_ID_OK_HIT_WINDOW, OkHitWindow);
|
|
||||||
yield return (ATTRIB_ID_MONO_STAMINA_FACTOR, MonoStaminaFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
||||||
{
|
{
|
||||||
base.FromDatabaseAttributes(values, onlineInfo);
|
MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[IDifficultyAttributes.ATTRIB_ID_DIFFICULTY];
|
||||||
StarRating = values[ATTRIB_ID_DIFFICULTY];
|
GreatHitWindow = values[IDifficultyAttributes.ATTRIB_ID_GREAT_HIT_WINDOW];
|
||||||
GreatHitWindow = values[ATTRIB_ID_GREAT_HIT_WINDOW];
|
OkHitWindow = values[IDifficultyAttributes.ATTRIB_ID_OK_HIT_WINDOW];
|
||||||
OkHitWindow = values[ATTRIB_ID_OK_HIT_WINDOW];
|
MonoStaminaFactor = values[IDifficultyAttributes.ATTRIB_ID_MONO_STAMINA_FACTOR];
|
||||||
MonoStaminaFactor = values[ATTRIB_ID_MONO_STAMINA_FACTOR];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,10 +72,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
return difficultyHitObjects;
|
return difficultyHitObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
if (beatmap.HitObjects.Count == 0)
|
if (beatmap.HitObjects.Count == 0)
|
||||||
return new TaikoDifficultyAttributes { Mods = mods };
|
return new TaikoDifficultyAttributes();
|
||||||
|
|
||||||
Colour colour = (Colour)skills.First(x => x is Colour);
|
Colour colour = (Colour)skills.First(x => x is Colour);
|
||||||
Rhythm rhythm = (Rhythm)skills.First(x => x is Rhythm);
|
Rhythm rhythm = (Rhythm)skills.First(x => x is Rhythm);
|
||||||
@ -106,7 +106,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes
|
TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes
|
||||||
{
|
{
|
||||||
StarRating = starRating,
|
StarRating = starRating,
|
||||||
Mods = mods,
|
|
||||||
StaminaDifficulty = staminaRating,
|
StaminaDifficulty = staminaRating,
|
||||||
MonoStaminaFactor = monoStaminaFactor,
|
MonoStaminaFactor = monoStaminaFactor,
|
||||||
RhythmDifficulty = rhythmRating,
|
RhythmDifficulty = rhythmRating,
|
||||||
|
@ -7,8 +7,14 @@ using osu.Game.Rulesets.Difficulty;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Taiko.Difficulty
|
namespace osu.Game.Rulesets.Taiko.Difficulty
|
||||||
{
|
{
|
||||||
public class TaikoPerformanceAttributes : PerformanceAttributes
|
public struct TaikoPerformanceAttributes : IPerformanceAttributes
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Calculated score performance points.
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty("pp")]
|
||||||
|
public double Total { get; set; }
|
||||||
|
|
||||||
[JsonProperty("difficulty")]
|
[JsonProperty("difficulty")]
|
||||||
public double Difficulty { get; set; }
|
public double Difficulty { get; set; }
|
||||||
|
|
||||||
@ -21,11 +27,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
[JsonProperty("estimated_unstable_rate")]
|
[JsonProperty("estimated_unstable_rate")]
|
||||||
public double? EstimatedUnstableRate { get; set; }
|
public double? EstimatedUnstableRate { get; set; }
|
||||||
|
|
||||||
public override IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||||
{
|
{
|
||||||
foreach (var attribute in base.GetAttributesForDisplay())
|
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||||
yield return attribute;
|
|
||||||
|
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Difficulty), "Difficulty", Difficulty);
|
yield return new PerformanceDisplayAttribute(nameof(Difficulty), "Difficulty", Difficulty);
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy);
|
yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes)
|
protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
{
|
{
|
||||||
var taikoAttributes = (TaikoDifficultyAttributes)attributes;
|
var taikoAttributes = (TaikoDifficultyAttributes)attributes;
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
|
|
||||||
protected override Mod[] DifficultyAdjustmentMods { get; }
|
protected override Mod[] DifficultyAdjustmentMods { get; }
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ namespace osu.Game.Tests.NonVisual
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
=> new TestDifficultyAttributes { Objects = beatmap.HitObjects.ToArray() };
|
=> new TestDifficultyAttributes { Objects = beatmap.HitObjects.ToArray() };
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
|
||||||
|
@ -208,8 +208,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
protected override IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate)
|
||||||
=> new DifficultyAttributes(mods, mods.OfType<TestMod>().SingleOrDefault()?.Difficulty.Value ?? 0);
|
=> new DifficultyAttributes { StarRating = mods.OfType<TestMod>().SingleOrDefault()?.Difficulty.Value ?? 0 };
|
||||||
|
|
||||||
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
|
protected override IEnumerable<DifficultyHitObject> CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate)
|
||||||
=> Array.Empty<DifficultyHitObject>();
|
=> Array.Empty<DifficultyHitObject>();
|
||||||
@ -225,7 +225,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes)
|
protected override IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
=> new PerformanceAttributes { Total = score.Mods.OfType<TestMod>().SingleOrDefault()?.Performance.Value ?? 0 };
|
=> new PerformanceAttributes { Total = score.Mods.OfType<TestMod>().SingleOrDefault()?.Performance.Value ?? 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,18 +22,18 @@ namespace osu.Game.Beatmaps
|
|||||||
/// The difficulty attributes computed for the given beatmap.
|
/// The difficulty attributes computed for the given beatmap.
|
||||||
/// Might not be available if the star difficulty is associated with a beatmap that's not locally available.
|
/// Might not be available if the star difficulty is associated with a beatmap that's not locally available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly DifficultyAttributes? DifficultyAttributes;
|
public readonly IDifficultyAttributes? DifficultyAttributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The performance attributes computed for a perfect score on the given beatmap.
|
/// The performance attributes computed for a perfect score on the given beatmap.
|
||||||
/// Might not be available if the star difficulty is associated with a beatmap that's not locally available.
|
/// Might not be available if the star difficulty is associated with a beatmap that's not locally available.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly PerformanceAttributes? PerformanceAttributes;
|
public readonly IPerformanceAttributes? PerformanceAttributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="StarDifficulty"/> structure.
|
/// Creates a <see cref="StarDifficulty"/> structure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StarDifficulty(DifficultyAttributes difficulty, PerformanceAttributes performance)
|
public StarDifficulty(IDifficultyAttributes difficulty, IPerformanceAttributes performance)
|
||||||
{
|
{
|
||||||
Stars = double.IsFinite(difficulty.StarRating) ? difficulty.StarRating : 0;
|
Stars = double.IsFinite(difficulty.StarRating) ? difficulty.StarRating : 0;
|
||||||
MaxCombo = difficulty.MaxCombo;
|
MaxCombo = difficulty.MaxCombo;
|
||||||
@ -44,7 +44,7 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a <see cref="StarDifficulty"/> structure with a pre-populated star difficulty and max combo
|
/// Creates a <see cref="StarDifficulty"/> structure with a pre-populated star difficulty and max combo
|
||||||
/// in scenarios where computing <see cref="Rulesets.Difficulty.DifficultyAttributes"/> is not feasible (i.e. when working with online sources).
|
/// in scenarios where computing <see cref="IDifficultyAttributes"/> is not feasible (i.e. when working with online sources).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public StarDifficulty(double starDifficulty, int maxCombo)
|
public StarDifficulty(double starDifficulty, int maxCombo)
|
||||||
{
|
{
|
||||||
|
@ -44,6 +44,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates");
|
public static LocalisableString CheckUpdate => new TranslatableString(getKey(@"check_update"), @"Check for updates");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Checking for updates"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString CheckingForUpdates => new TranslatableString(getKey(@"checking_for_updates"), @"Checking for updates");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Open osu! folder"
|
/// "Open osu! folder"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
@ -13,6 +12,7 @@ using osu.Framework.Screens;
|
|||||||
using osu.Framework.Statistics;
|
using osu.Framework.Statistics;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
using osu.Game.Overlays.Settings.Sections.Maintenance;
|
||||||
using osu.Game.Updater;
|
using osu.Game.Updater;
|
||||||
@ -36,8 +36,11 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private Storage storage { get; set; } = null!;
|
private Storage storage { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuGame? game { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuConfigManager config, OsuGame? game)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
Add(new SettingsEnumDropdown<ReleaseStream>
|
Add(new SettingsEnumDropdown<ReleaseStream>
|
||||||
{
|
{
|
||||||
@ -50,23 +53,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Add(checkForUpdatesButton = new SettingsButton
|
Add(checkForUpdatesButton = new SettingsButton
|
||||||
{
|
{
|
||||||
Text = GeneralSettingsStrings.CheckUpdate,
|
Text = GeneralSettingsStrings.CheckUpdate,
|
||||||
Action = () =>
|
Action = () => checkForUpdates().FireAndForget()
|
||||||
{
|
|
||||||
checkForUpdatesButton.Enabled.Value = false;
|
|
||||||
Task.Run(updateManager.CheckForUpdateAsync).ContinueWith(task => Schedule(() =>
|
|
||||||
{
|
|
||||||
if (!task.GetResultSafely())
|
|
||||||
{
|
|
||||||
notifications?.Post(new SimpleNotification
|
|
||||||
{
|
|
||||||
Text = GeneralSettingsStrings.RunningLatestRelease(game!.Version),
|
|
||||||
Icon = FontAwesome.Solid.CheckCircle,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
checkForUpdatesButton.Enabled.Value = true;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +81,44 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task checkForUpdates()
|
||||||
|
{
|
||||||
|
if (updateManager == null || game == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
checkForUpdatesButton.Enabled.Value = false;
|
||||||
|
|
||||||
|
var checkingNotification = new ProgressNotification
|
||||||
|
{
|
||||||
|
Text = GeneralSettingsStrings.CheckingForUpdates,
|
||||||
|
};
|
||||||
|
notifications?.Post(checkingNotification);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool foundUpdate = await updateManager.CheckForUpdateAsync().ConfigureAwait(true);
|
||||||
|
|
||||||
|
if (!foundUpdate)
|
||||||
|
{
|
||||||
|
notifications?.Post(new SimpleNotification
|
||||||
|
{
|
||||||
|
Text = GeneralSettingsStrings.RunningLatestRelease(game.Version),
|
||||||
|
Icon = FontAwesome.Solid.CheckCircle,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// This sequence allows the notification to be immediately dismissed.
|
||||||
|
checkingNotification.State = ProgressNotificationState.Cancelled;
|
||||||
|
checkingNotification.Close(false);
|
||||||
|
checkForUpdatesButton.Enabled.Value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void exportLogs()
|
private void exportLogs()
|
||||||
{
|
{
|
||||||
ProgressNotification notification = new ProgressNotification
|
ProgressNotification notification = new ProgressNotification
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>A structure describing the difficulty of the beatmap.</returns>
|
/// <returns>A structure describing the difficulty of the beatmap.</returns>
|
||||||
public DifficultyAttributes Calculate(CancellationToken cancellationToken = default)
|
public IDifficultyAttributes Calculate(CancellationToken cancellationToken = default)
|
||||||
=> Calculate(Array.Empty<Mod>(), cancellationToken);
|
=> Calculate(Array.Empty<Mod>(), cancellationToken);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -60,7 +60,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// <param name="mods">The mods that should be applied to the beatmap.</param>
|
/// <param name="mods">The mods that should be applied to the beatmap.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>A structure describing the difficulty of the beatmap.</returns>
|
/// <returns>A structure describing the difficulty of the beatmap.</returns>
|
||||||
public DifficultyAttributes Calculate([NotNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default)
|
public IDifficultyAttributes Calculate([NotNull] IEnumerable<Mod> mods, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
preProcess(mods, cancellationToken);
|
preProcess(mods, cancellationToken);
|
||||||
@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// This can only be used to compute difficulties for legacy mod combinations.
|
/// This can only be used to compute difficulties for legacy mod combinations.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <returns>A collection of structures describing the difficulty of the beatmap for each mod combination.</returns>
|
/// <returns>A collection of structures describing the difficulty of the beatmap for each mod combination.</returns>
|
||||||
public IEnumerable<DifficultyAttributes> CalculateAllLegacyCombinations(CancellationToken cancellationToken = default)
|
public IEnumerable<(Mod[] Mods, IDifficultyAttributes Attributes)> CalculateAllLegacyCombinations(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var rulesetInstance = ruleset.CreateInstance();
|
var rulesetInstance = ruleset.CreateInstance();
|
||||||
|
|
||||||
@ -148,11 +148,13 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
{
|
{
|
||||||
Mod classicMod = rulesetInstance.CreateMod<ModClassic>();
|
Mod classicMod = rulesetInstance.CreateMod<ModClassic>();
|
||||||
|
|
||||||
var finalCombination = ModUtils.FlattenMod(combination);
|
IEnumerable<Mod> finalCombination = ModUtils.FlattenMod(combination);
|
||||||
if (classicMod != null)
|
if (classicMod != null)
|
||||||
finalCombination = finalCombination.Append(classicMod);
|
finalCombination = finalCombination.Append(classicMod);
|
||||||
|
|
||||||
yield return Calculate(finalCombination.ToArray(), cancellationToken);
|
Mod[] finalMods = finalCombination.ToArray();
|
||||||
|
|
||||||
|
yield return (finalMods, Calculate(finalMods, cancellationToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,14 +265,14 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty<Mod>();
|
protected virtual Mod[] DifficultyAdjustmentMods => Array.Empty<Mod>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates <see cref="DifficultyAttributes"/> to describe beatmap's calculated difficulty.
|
/// Creates <see cref="IDifficultyAttributes"/> to describe beatmap's calculated difficulty.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="beatmap">The <see cref="IBeatmap"/> whose difficulty was calculated.
|
/// <param name="beatmap">The <see cref="IBeatmap"/> whose difficulty was calculated.
|
||||||
/// This may differ from <see cref="Beatmap"/> in the case of timed calculation.</param>
|
/// This may differ from <see cref="Beatmap"/> in the case of timed calculation.</param>
|
||||||
/// <param name="mods">The <see cref="Mod"/>s that difficulty was calculated with.</param>
|
/// <param name="mods">The <see cref="Mod"/>s that difficulty was calculated with.</param>
|
||||||
/// <param name="skills">The skills which processed the beatmap.</param>
|
/// <param name="skills">The skills which processed the beatmap.</param>
|
||||||
/// <param name="clockRate">The rate at which the gameplay clock is run at.</param>
|
/// <param name="clockRate">The rate at which the gameplay clock is run at.</param>
|
||||||
protected abstract DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate);
|
protected abstract IDifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enumerates <see cref="DifficultyHitObject"/>s to be processed from <see cref="HitObject"/>s in the <see cref="IBeatmap"/>.
|
/// Enumerates <see cref="DifficultyHitObject"/>s to be processed from <see cref="HitObject"/>s in the <see cref="IBeatmap"/>.
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Mods;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Difficulty
|
namespace osu.Game.Rulesets.Difficulty
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the difficulty of a beatmap, as output by a <see cref="DifficultyCalculator"/>.
|
/// Describes the difficulty of a beatmap, as output by a <see cref="DifficultyCalculator"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonObject(MemberSerialization.OptIn)]
|
public interface IDifficultyAttributes
|
||||||
public class DifficultyAttributes
|
|
||||||
{
|
{
|
||||||
protected const int ATTRIB_ID_AIM = 1;
|
protected const int ATTRIB_ID_AIM = 1;
|
||||||
protected const int ATTRIB_ID_SPEED = 3;
|
protected const int ATTRIB_ID_SPEED = 3;
|
||||||
@ -31,11 +28,6 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
protected const int ATTRIB_ID_OK_HIT_WINDOW = 27;
|
protected const int ATTRIB_ID_OK_HIT_WINDOW = 27;
|
||||||
protected const int ATTRIB_ID_MONO_STAMINA_FACTOR = 29;
|
protected const int ATTRIB_ID_MONO_STAMINA_FACTOR = 29;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The mods which were applied to the beatmap.
|
|
||||||
/// </summary>
|
|
||||||
public Mod[] Mods { get; set; } = Array.Empty<Mod>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The combined star rating of all skills.
|
/// The combined star rating of all skills.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -49,42 +41,40 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
public int MaxCombo { get; set; }
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new <see cref="DifficultyAttributes"/>.
|
/// Converts this <see cref="IDifficultyAttributes"/> to osu-web compatible database attribute mappings.
|
||||||
/// </summary>
|
|
||||||
public DifficultyAttributes()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates new <see cref="DifficultyAttributes"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mods">The mods which were applied to the beatmap.</param>
|
|
||||||
/// <param name="starRating">The combined star rating of all skills.</param>
|
|
||||||
public DifficultyAttributes(Mod[] mods, double starRating)
|
|
||||||
{
|
|
||||||
Mods = mods;
|
|
||||||
StarRating = starRating;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts this <see cref="DifficultyAttributes"/> to osu-web compatible database attribute mappings.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See: osu_difficulty_attribs table.
|
/// See: osu_difficulty_attribs table.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes();
|
||||||
{
|
|
||||||
yield return (ATTRIB_ID_MAX_COMBO, MaxCombo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads osu-web database attribute mappings into this <see cref="DifficultyAttributes"/> object.
|
/// Reads osu-web database attribute mappings into this <see cref="IDifficultyAttributes"/> object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="values">The attribute mappings.</param>
|
/// <param name="values">The attribute mappings.</param>
|
||||||
/// <param name="onlineInfo">The <see cref="IBeatmapOnlineInfo"/> where more information about the beatmap may be extracted from (such as AR/CS/OD/etc).</param>
|
/// <param name="onlineInfo">The <see cref="IBeatmapOnlineInfo"/> where more information about the beatmap may be extracted from (such as AR/CS/OD/etc).</param>
|
||||||
public virtual void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a full, minimal implementation of <see cref="IDifficultyAttributes"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class DifficultyAttributes : IDifficultyAttributes
|
||||||
{
|
{
|
||||||
MaxCombo = (int)values[ATTRIB_ID_MAX_COMBO];
|
public double StarRating { get; set; }
|
||||||
|
|
||||||
|
public int MaxCombo { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<(int attributeId, object value)> ToDatabaseAttributes()
|
||||||
|
{
|
||||||
|
yield return (IDifficultyAttributes.ATTRIB_ID_MAX_COMBO, MaxCombo);
|
||||||
|
yield return (IDifficultyAttributes.ATTRIB_ID_AIM, StarRating);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FromDatabaseAttributes(IReadOnlyDictionary<int, double> values, IBeatmapOnlineInfo onlineInfo)
|
||||||
|
{
|
||||||
|
MaxCombo = (int)values[IDifficultyAttributes.ATTRIB_ID_MAX_COMBO];
|
||||||
|
StarRating = values[IDifficultyAttributes.ATTRIB_ID_AIM];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ using Newtonsoft.Json;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Difficulty
|
namespace osu.Game.Rulesets.Difficulty
|
||||||
{
|
{
|
||||||
public class PerformanceAttributes
|
public interface IPerformanceAttributes
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculated score performance points.
|
/// Calculated score performance points.
|
||||||
@ -19,7 +19,17 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// Some attributes may be omitted if they are not meant for display.
|
/// Some attributes may be omitted if they are not meant for display.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a full, minimal implementation of <see cref="IPerformanceAttributes"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class PerformanceAttributes : IPerformanceAttributes
|
||||||
|
{
|
||||||
|
public double Total { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<PerformanceDisplayAttribute> GetAttributesForDisplay()
|
||||||
{
|
{
|
||||||
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
yield return new PerformanceDisplayAttribute(nameof(Total), "Achieved PP", Total);
|
||||||
}
|
}
|
@ -11,19 +11,19 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Actual gameplay performance.
|
/// Actual gameplay performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PerformanceAttributes Performance { get; set; }
|
public IPerformanceAttributes Performance { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performance of a perfect play for comparison.
|
/// Performance of a perfect play for comparison.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PerformanceAttributes PerfectPerformance { get; set; }
|
public IPerformanceAttributes PerfectPerformance { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new performance breakdown.
|
/// Create a new performance breakdown.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="performance">Actual gameplay performance.</param>
|
/// <param name="performance">Actual gameplay performance.</param>
|
||||||
/// <param name="perfectPerformance">Performance of a perfect play for comparison.</param>
|
/// <param name="perfectPerformance">Performance of a perfect play for comparison.</param>
|
||||||
public PerformanceBreakdown(PerformanceAttributes performance, PerformanceAttributes perfectPerformance)
|
public PerformanceBreakdown(IPerformanceAttributes performance, IPerformanceAttributes perfectPerformance)
|
||||||
{
|
{
|
||||||
Performance = performance;
|
Performance = performance;
|
||||||
PerfectPerformance = perfectPerformance;
|
PerfectPerformance = perfectPerformance;
|
||||||
|
@ -17,20 +17,20 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
Ruleset = ruleset;
|
Ruleset = ruleset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<PerformanceAttributes> CalculateAsync(ScoreInfo score, DifficultyAttributes attributes, CancellationToken cancellationToken)
|
public Task<IPerformanceAttributes> CalculateAsync(ScoreInfo score, IDifficultyAttributes attributes, CancellationToken cancellationToken)
|
||||||
=> Task.Run(() => CreatePerformanceAttributes(score, attributes), cancellationToken);
|
=> Task.Run(() => CreatePerformanceAttributes(score, attributes), cancellationToken);
|
||||||
|
|
||||||
public PerformanceAttributes Calculate(ScoreInfo score, DifficultyAttributes attributes)
|
public IPerformanceAttributes Calculate(ScoreInfo score, IDifficultyAttributes attributes)
|
||||||
=> CreatePerformanceAttributes(score, attributes);
|
=> CreatePerformanceAttributes(score, attributes);
|
||||||
|
|
||||||
public PerformanceAttributes Calculate(ScoreInfo score, IWorkingBeatmap beatmap)
|
public IPerformanceAttributes Calculate(ScoreInfo score, IWorkingBeatmap beatmap)
|
||||||
=> Calculate(score, Ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods));
|
=> Calculate(score, Ruleset.CreateDifficultyCalculator(beatmap).Calculate(score.Mods));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates <see cref="PerformanceAttributes"/> to describe a score's performance.
|
/// Creates <see cref="IPerformanceAttributes"/> to describe a score's performance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="score">The score to create the attributes for.</param>
|
/// <param name="score">The score to create the attributes for.</param>
|
||||||
/// <param name="attributes">The difficulty attributes for the beatmap relating to the score.</param>
|
/// <param name="attributes">The difficulty attributes for the beatmap relating to the score.</param>
|
||||||
protected abstract PerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, DifficultyAttributes attributes);
|
protected abstract IPerformanceAttributes CreatePerformanceAttributes(ScoreInfo score, IDifficultyAttributes attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
public class PerformanceDisplayAttribute
|
public class PerformanceDisplayAttribute
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Name of the attribute property in <see cref="PerformanceAttributes"/>.
|
/// Name of the attribute property in <see cref="IPerformanceAttributes"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string PropertyName { get; }
|
public string PropertyName { get; }
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ using System;
|
|||||||
namespace osu.Game.Rulesets.Difficulty
|
namespace osu.Game.Rulesets.Difficulty
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wraps a <see cref="DifficultyAttributes"/> object and adds a time value for which the attribute is valid.
|
/// Wraps a <see cref="IDifficultyAttributes"/> object and adds a time value for which the attribute is valid.
|
||||||
/// Output by DifficultyCalculator.CalculateTimed methods.
|
/// Output by DifficultyCalculator.CalculateTimed methods.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TimedDifficultyAttributes : IComparable<TimedDifficultyAttributes>
|
public class TimedDifficultyAttributes : IComparable<TimedDifficultyAttributes>
|
||||||
@ -21,14 +21,14 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The attributes.
|
/// The attributes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly DifficultyAttributes Attributes;
|
public readonly IDifficultyAttributes Attributes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates new <see cref="TimedDifficultyAttributes"/>.
|
/// Creates new <see cref="TimedDifficultyAttributes"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The non-clock-adjusted time value at which the attributes take effect.</param>
|
/// <param name="time">The non-clock-adjusted time value at which the attributes take effect.</param>
|
||||||
/// <param name="attributes">The attributes.</param>
|
/// <param name="attributes">The attributes.</param>
|
||||||
public TimedDifficultyAttributes(double time, DifficultyAttributes attributes)
|
public TimedDifficultyAttributes(double time, IDifficultyAttributes attributes)
|
||||||
{
|
{
|
||||||
Time = time;
|
Time = time;
|
||||||
Attributes = attributes;
|
Attributes = attributes;
|
||||||
|
@ -106,7 +106,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
}
|
}
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private DifficultyAttributes getAttributeAtTime(JudgementResult judgement)
|
private IDifficultyAttributes getAttributeAtTime(JudgementResult judgement)
|
||||||
{
|
{
|
||||||
if (timedAttributes == null || timedAttributes.Count == 0)
|
if (timedAttributes == null || timedAttributes.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
|
@ -176,8 +176,8 @@ namespace osu.Game.Screens.Ranking.Statistics
|
|||||||
var perfectDisplayAttributes = breakdown.PerfectPerformance.GetAttributesForDisplay();
|
var perfectDisplayAttributes = breakdown.PerfectPerformance.GetAttributesForDisplay();
|
||||||
|
|
||||||
setTotalValues(
|
setTotalValues(
|
||||||
displayAttributes.First(a => a.PropertyName == nameof(PerformanceAttributes.Total)),
|
displayAttributes.First(a => a.PropertyName == nameof(IPerformanceAttributes.Total)),
|
||||||
perfectDisplayAttributes.First(a => a.PropertyName == nameof(PerformanceAttributes.Total))
|
perfectDisplayAttributes.First(a => a.PropertyName == nameof(IPerformanceAttributes.Total))
|
||||||
);
|
);
|
||||||
|
|
||||||
var rowDimensions = new List<Dimension>();
|
var rowDimensions = new List<Dimension>();
|
||||||
@ -185,7 +185,7 @@ namespace osu.Game.Screens.Ranking.Statistics
|
|||||||
|
|
||||||
foreach (PerformanceDisplayAttribute attr in displayAttributes)
|
foreach (PerformanceDisplayAttribute attr in displayAttributes)
|
||||||
{
|
{
|
||||||
if (attr.PropertyName == nameof(PerformanceAttributes.Total)) continue;
|
if (attr.PropertyName == nameof(IPerformanceAttributes.Total)) continue;
|
||||||
|
|
||||||
var row = createAttributeRow(attr, perfectDisplayAttributes.First(a => a.PropertyName == attr.PropertyName));
|
var row = createAttributeRow(attr, perfectDisplayAttributes.First(a => a.PropertyName == attr.PropertyName));
|
||||||
|
|
||||||
|
@ -25,14 +25,14 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
protected void Test(double expectedStarRating, int expectedMaxCombo, string name, params Mod[] mods)
|
protected void Test(double expectedStarRating, int expectedMaxCombo, string name, params Mod[] mods)
|
||||||
{
|
{
|
||||||
var attributes = CreateDifficultyCalculator(getBeatmap(name)).Calculate(mods);
|
var attributes = CreateDifficultyCalculator(GetBeatmap(name)).Calculate(mods);
|
||||||
|
|
||||||
// Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences.
|
// Platform-dependent math functions (Pow, Cbrt, Exp, etc) may result in minute differences.
|
||||||
Assert.That(attributes.StarRating, Is.EqualTo(expectedStarRating).Within(0.00001));
|
Assert.That(attributes.StarRating, Is.EqualTo(expectedStarRating).Within(0.00001));
|
||||||
Assert.That(attributes.MaxCombo, Is.EqualTo(expectedMaxCombo));
|
Assert.That(attributes.MaxCombo, Is.EqualTo(expectedMaxCombo));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IWorkingBeatmap getBeatmap(string name)
|
protected IWorkingBeatmap GetBeatmap(string name)
|
||||||
{
|
{
|
||||||
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
||||||
using (var stream = new LineBufferedReader(resStream))
|
using (var stream = new LineBufferedReader(resStream))
|
||||||
|
Loading…
Reference in New Issue
Block a user