From 52c7de8ac952e6207c3caa3f7685720fdc9a5177 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 18:28:45 +0200 Subject: [PATCH 1/4] initial commit --- PerformanceCalculatorGUI/RulesetHelper.cs | 49 ++++++++++++++----- .../Screens/SimulateScreen.cs | 15 ++++-- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/PerformanceCalculatorGUI/RulesetHelper.cs b/PerformanceCalculatorGUI/RulesetHelper.cs index 1529d0390..a59872fc2 100644 --- a/PerformanceCalculatorGUI/RulesetHelper.cs +++ b/PerformanceCalculatorGUI/RulesetHelper.cs @@ -21,6 +21,7 @@ using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Skinning; using osu.Game.Utils; +using osuTK; namespace PerformanceCalculatorGUI { @@ -104,7 +105,7 @@ public static int AdjustManiaScore(int score, IReadOnlyList mods) return (int)Math.Round(1000000 * scoreMultiplier); } - public static Dictionary GenerateHitResultsForRuleset(RulesetInfo ruleset, double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood, int countLargeTickMisses, int countSliderTailMisses) + public static Dictionary GenerateHitResultsForRuleset(RulesetInfo ruleset, double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood, int? countLargeTickMisses, int? countSliderTailMisses) { return ruleset.OnlineID switch { @@ -116,7 +117,7 @@ public static Dictionary GenerateHitResultsForRuleset(RulesetInf }; } - private static Dictionary generateOsuHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood, int countLargeTickMisses, int countSliderTailMisses) + private static Dictionary generateOsuHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood, int? countLargeTickMisses, int? countSliderTailMisses) { int countGreat; @@ -192,17 +193,21 @@ private static Dictionary generateOsuHitResults(double accuracy, countGreat = (int)(totalResultCount - countGood - countMeh - countMiss); } - int sliderTailHits = beatmap.HitObjects.Count(x => x is Slider) - countSliderTailMisses; - - return new Dictionary + var result = new Dictionary { { HitResult.Great, countGreat }, { HitResult.Ok, countGood ?? 0 }, { HitResult.Meh, countMeh ?? 0 }, - { HitResult.LargeTickMiss, countLargeTickMisses }, - { HitResult.SliderTailHit, sliderTailHits }, { HitResult.Miss, countMiss } }; + + if (countLargeTickMisses != null) + result[HitResult.LargeTickMiss] = countLargeTickMisses.Value; + + if (countSliderTailMisses != null) + result[HitResult.SliderTailHit] = beatmap.HitObjects.Count(x => x is Slider) - countSliderTailMisses.Value; + + return result; } private static Dictionary generateTaikoHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countGood) @@ -293,11 +298,11 @@ private static Dictionary generateManiaHitResults(double accurac }; } - public static double GetAccuracyForRuleset(RulesetInfo ruleset, Dictionary statistics) + public static double GetAccuracyForRuleset(RulesetInfo ruleset, IBeatmap beatmap, Dictionary statistics) { return ruleset.OnlineID switch { - 0 => getOsuAccuracy(statistics), + 0 => getOsuAccuracy(beatmap, statistics), 1 => getTaikoAccuracy(statistics), 2 => getCatchAccuracy(statistics), 3 => getManiaAccuracy(statistics), @@ -305,15 +310,35 @@ public static double GetAccuracyForRuleset(RulesetInfo ruleset, Dictionary statistics) + private static double getOsuAccuracy(IBeatmap beatmap, Dictionary statistics) { var countGreat = statistics[HitResult.Great]; var countGood = statistics[HitResult.Ok]; var countMeh = statistics[HitResult.Meh]; var countMiss = statistics[HitResult.Miss]; - var total = countGreat + countGood + countMeh + countMiss; - return (double)((6 * countGreat) + (2 * countGood) + countMeh) / (6 * total); + double total = 6 * countGreat + 2 * countGood + countMeh; + double max = 6 * (countGreat + countGood + countMeh + countMiss); + + if (statistics.ContainsKey(HitResult.SliderTailHit)) + { + var countSliders = beatmap.HitObjects.Count(x => x is Slider); + var countSliderTailHit = statistics[HitResult.SliderTailHit]; + + total += 3 * countSliderTailHit; + max += 3 * countSliders; + } + + if (statistics.ContainsKey(HitResult.LargeTickMiss)) + { + var countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat)); + var countLargeTickHit = countLargeTicks - statistics[HitResult.LargeTickMiss]; + + total += 0.6 * countLargeTickHit; + max += 0.6 * countLargeTicks; + } + + return total / max; } private static double getTaikoAccuracy(Dictionary statistics) diff --git a/PerformanceCalculatorGUI/Screens/SimulateScreen.cs b/PerformanceCalculatorGUI/Screens/SimulateScreen.cs index 166e3be57..cfd1fe33d 100644 --- a/PerformanceCalculatorGUI/Screens/SimulateScreen.cs +++ b/PerformanceCalculatorGUI/Screens/SimulateScreen.cs @@ -702,10 +702,19 @@ private void calculatePerformance() if (ruleset.Value.OnlineID != -1) { // official rulesets can generate more precise hits from accuracy - statistics = RulesetHelper.GenerateHitResultsForRuleset(ruleset.Value, accuracyTextBox.Value.Value / 100.0, beatmap, missesTextBox.Value.Value, countMeh, countGood, - largeTickMissesTextBox.Value.Value, sliderTailMissesTextBox.Value.Value); + if (appliedMods.Value.OfType().Any(m => m.NoSliderHeadAccuracy.Value)) + { + statistics = RulesetHelper.GenerateHitResultsForRuleset(ruleset.Value, accuracyTextBox.Value.Value / 100.0, beatmap, missesTextBox.Value.Value, countMeh, countGood, + null, null); + } + else + { + statistics = RulesetHelper.GenerateHitResultsForRuleset(ruleset.Value, accuracyTextBox.Value.Value / 100.0, beatmap, missesTextBox.Value.Value, countMeh, countGood, + largeTickMissesTextBox.Value.Value, sliderTailMissesTextBox.Value.Value); + } + - accuracy = RulesetHelper.GetAccuracyForRuleset(ruleset.Value, statistics); + accuracy = RulesetHelper.GetAccuracyForRuleset(ruleset.Value, beatmap, statistics); } var ppAttributes = performanceCalculator?.Calculate(new ScoreInfo(beatmap.BeatmapInfo, ruleset.Value) From 15d4f78974c7352906f0fb21b97f74b37cbd7711 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 18:29:22 +0200 Subject: [PATCH 2/4] Update RulesetHelper.cs --- PerformanceCalculatorGUI/RulesetHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/PerformanceCalculatorGUI/RulesetHelper.cs b/PerformanceCalculatorGUI/RulesetHelper.cs index a59872fc2..d879fc219 100644 --- a/PerformanceCalculatorGUI/RulesetHelper.cs +++ b/PerformanceCalculatorGUI/RulesetHelper.cs @@ -21,7 +21,6 @@ using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Skinning; using osu.Game.Utils; -using osuTK; namespace PerformanceCalculatorGUI { From 750e377034972f0cd810c41a18d71d4acca63c77 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 19:03:18 +0200 Subject: [PATCH 3/4] add mod-specific behaviour --- .../Simulate/CatchSimulateCommand.cs | 3 ++- .../Simulate/ManiaSimulateCommand.cs | 3 ++- .../Simulate/OsuSimulateCommand.cs | 14 +++++++++++++- PerformanceCalculator/Simulate/SimulateCommand.cs | 5 +++-- .../Simulate/TaikoSimulateCommand.cs | 3 ++- 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/PerformanceCalculator/Simulate/CatchSimulateCommand.cs b/PerformanceCalculator/Simulate/CatchSimulateCommand.cs index 146508f5c..86fa47101 100644 --- a/PerformanceCalculator/Simulate/CatchSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/CatchSimulateCommand.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Catch.Objects; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using System; using System.Collections.Generic; @@ -35,7 +36,7 @@ public class CatchSimulateCommand : SimulateCommand public override Ruleset Ruleset => new CatchRuleset(); - protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods); + protected override Dictionary GenerateHitResults(IBeatmap beatmap, Mod[] mods) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods); private static Dictionary generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countGood) { diff --git a/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs b/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs index 61c7f74a6..0287c50df 100644 --- a/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Mania.Objects; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; namespace PerformanceCalculator.Simulate @@ -35,7 +36,7 @@ public class ManiaSimulateCommand : SimulateCommand public override Ruleset Ruleset => new ManiaRuleset(); - protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, oks, Goods, greats); + protected override Dictionary GenerateHitResults(IBeatmap beatmap, Mod[] mods) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, oks, Goods, greats); private static Dictionary generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countOk, int? countGood, int? countGreat) { diff --git a/PerformanceCalculator/Simulate/OsuSimulateCommand.cs b/PerformanceCalculator/Simulate/OsuSimulateCommand.cs index fd3b1c548..246897b37 100644 --- a/PerformanceCalculator/Simulate/OsuSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/OsuSimulateCommand.cs @@ -8,7 +8,9 @@ using McMaster.Extensions.CommandLineUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Scoring; @@ -43,7 +45,17 @@ public class OsuSimulateCommand : SimulateCommand public override Ruleset Ruleset => new OsuRuleset(); - protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods, largeTickMisses, sliderTailMisses); + protected override Dictionary GenerateHitResults(IBeatmap beatmap, Mod[] mods) + { + if (mods.OfType().Any(m => m.NoSliderHeadAccuracy.Value)) + { + return generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods, null, null); + } + else + { + return generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods, largeTickMisses, sliderTailMisses); + } + } private static Dictionary generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countGood, int? countLargeTickMisses, int? countSliderTailMisses) { diff --git a/PerformanceCalculator/Simulate/SimulateCommand.cs b/PerformanceCalculator/Simulate/SimulateCommand.cs index be319ad99..6f17cf634 100644 --- a/PerformanceCalculator/Simulate/SimulateCommand.cs +++ b/PerformanceCalculator/Simulate/SimulateCommand.cs @@ -8,6 +8,7 @@ using McMaster.Extensions.CommandLineUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; @@ -66,7 +67,7 @@ public override void Execute() var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo); var beatmapMaxCombo = beatmap.GetMaxCombo(); - var statistics = GenerateHitResults(beatmap); + var statistics = GenerateHitResults(beatmap, mods); var scoreInfo = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo) { Accuracy = GetAccuracy(beatmap, statistics), @@ -83,7 +84,7 @@ public override void Execute() OutputPerformance(scoreInfo, performanceAttributes, difficultyAttributes); } - protected abstract Dictionary GenerateHitResults(IBeatmap beatmap); + protected abstract Dictionary GenerateHitResults(IBeatmap beatmap, Mod[] mods); protected virtual double GetAccuracy(IBeatmap beatmap, Dictionary statistics) => 0; } diff --git a/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs b/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs index ac7d69448..bf537a7c8 100644 --- a/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs @@ -7,6 +7,7 @@ using McMaster.Extensions.CommandLineUtils; using osu.Game.Beatmaps; using osu.Game.Rulesets; +using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko; @@ -29,7 +30,7 @@ public class TaikoSimulateCommand : SimulateCommand public override Ruleset Ruleset => new TaikoRuleset(); - protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(Accuracy / 100, beatmap, Misses, Goods); + protected override Dictionary GenerateHitResults(IBeatmap beatmap, Mod[] mods) => generateHitResults(Accuracy / 100, beatmap, Misses, Goods); private static Dictionary generateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countGood) { From ee6b7c2bd6413d0b2bd2c5d8cc1a68eba72d610e Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 19:03:57 +0200 Subject: [PATCH 4/4] fix CI --- PerformanceCalculatorGUI/Screens/SimulateScreen.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/PerformanceCalculatorGUI/Screens/SimulateScreen.cs b/PerformanceCalculatorGUI/Screens/SimulateScreen.cs index cfd1fe33d..c067745a5 100644 --- a/PerformanceCalculatorGUI/Screens/SimulateScreen.cs +++ b/PerformanceCalculatorGUI/Screens/SimulateScreen.cs @@ -712,7 +712,6 @@ private void calculatePerformance() statistics = RulesetHelper.GenerateHitResultsForRuleset(ruleset.Value, accuracyTextBox.Value.Value / 100.0, beatmap, missesTextBox.Value.Value, countMeh, countGood, largeTickMissesTextBox.Value.Value, sliderTailMissesTextBox.Value.Value); } - accuracy = RulesetHelper.GetAccuracyForRuleset(ruleset.Value, beatmap, statistics); }