From 66b20a6fdd3026c6e2cac5fd15a367df1931420a Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 19:02:02 +0200 Subject: [PATCH 1/2] initial commit --- .../Simulate/CatchSimulateCommand.cs | 4 +- .../Simulate/ManiaSimulateCommand.cs | 28 +++++++------ .../Simulate/OsuSimulateCommand.cs | 42 ++++++++++++++----- .../Simulate/SimulateCommand.cs | 6 +-- .../Simulate/TaikoSimulateCommand.cs | 4 +- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/PerformanceCalculator/Simulate/CatchSimulateCommand.cs b/PerformanceCalculator/Simulate/CatchSimulateCommand.cs index f2fb26958..146508f5c 100644 --- a/PerformanceCalculator/Simulate/CatchSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/CatchSimulateCommand.cs @@ -35,7 +35,9 @@ public class CatchSimulateCommand : SimulateCommand public override Ruleset Ruleset => new CatchRuleset(); - protected override Dictionary GenerateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood) + protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(beatmap, Accuracy / 100, Misses, Mehs, Goods); + + private static Dictionary generateHitResults(IBeatmap beatmap, double accuracy, int countMiss, int? countMeh, int? countGood) { var maxCombo = beatmap.GetMaxCombo(); int maxTinyDroplets = beatmap.HitObjects.OfType().Sum(s => s.NestedHitObjects.OfType().Count()); diff --git a/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs b/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs index 22ed21a4a..61c7f74a6 100644 --- a/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/ManiaSimulateCommand.cs @@ -35,21 +35,23 @@ public class ManiaSimulateCommand : SimulateCommand public override Ruleset Ruleset => new ManiaRuleset(); - protected override Dictionary GenerateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood) + protected override Dictionary GenerateHitResults(IBeatmap beatmap) => 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) { // One judgement per normal note. Two judgements per hold note (head + tail). var totalHits = beatmap.HitObjects.Count + beatmap.HitObjects.Count(ho => ho is HoldNote); - if (countMeh != null || oks != null || countGood != null || greats != null) + if (countMeh != null || countOk != null || countGood != null || countGreat != null) { - int countPerfect = totalHits - (countMiss + (countMeh ?? 0) + (oks ?? 0) + (countGood ?? 0) + (greats ?? 0)); + int countPerfect = totalHits - (countMiss + (countMeh ?? 0) + (countOk ?? 0) + (countGood ?? 0) + (countGreat ?? 0)); return new Dictionary { [HitResult.Perfect] = countPerfect, - [HitResult.Great] = greats ?? 0, + [HitResult.Great] = countGreat ?? 0, [HitResult.Good] = countGood ?? 0, - [HitResult.Ok] = oks ?? 0, + [HitResult.Ok] = countOk ?? 0, [HitResult.Meh] = countMeh ?? 0, [HitResult.Miss] = countMiss }; @@ -66,10 +68,10 @@ protected override Dictionary GenerateHitResults(double accuracy // Each great and perfect increases total by 5 (great-meh=5) // There is no difference in accuracy between them, so just halve arbitrarily (favouring perfects for an odd number). int greatsAndPerfects = Math.Min(delta / 5, remainingHits); - int countGreat = greatsAndPerfects / 2; - int perfects = greatsAndPerfects - countGreat; - delta -= (countGreat + perfects) * 5; - remainingHits -= countGreat + perfects; + int greats = greatsAndPerfects / 2; + int perfects = greatsAndPerfects - greats; + delta -= (greats + perfects) * 5; + remainingHits -= greats + perfects; // Each good increases total by 3 (good-meh=3). countGood = Math.Min(delta / 3, remainingHits); @@ -77,8 +79,8 @@ protected override Dictionary GenerateHitResults(double accuracy remainingHits -= countGood.Value; // Each ok increases total by 1 (ok-meh=1). - int countOk = delta; - remainingHits -= countOk; + int oks = delta; + remainingHits -= oks; // Everything else is a meh, as initially assumed. countMeh = remainingHits; @@ -86,8 +88,8 @@ protected override Dictionary GenerateHitResults(double accuracy return new Dictionary { { HitResult.Perfect, perfects }, - { HitResult.Great, countGreat }, - { HitResult.Ok, countOk }, + { HitResult.Great, greats }, + { HitResult.Ok, oks }, { HitResult.Good, countGood.Value }, { HitResult.Meh, countMeh.Value }, { HitResult.Miss, countMiss } diff --git a/PerformanceCalculator/Simulate/OsuSimulateCommand.cs b/PerformanceCalculator/Simulate/OsuSimulateCommand.cs index 1b76cb0af..fd3b1c548 100644 --- a/PerformanceCalculator/Simulate/OsuSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/OsuSimulateCommand.cs @@ -43,7 +43,9 @@ public class OsuSimulateCommand : SimulateCommand public override Ruleset Ruleset => new OsuRuleset(); - protected override Dictionary GenerateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood) + protected override Dictionary GenerateHitResults(IBeatmap beatmap) => 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) { int countGreat; @@ -119,15 +121,21 @@ protected override Dictionary GenerateHitResults(double accuracy countGreat = (int)(totalResultCount - countGood - countMeh - countMiss); } - return new Dictionary + var result = new Dictionary { { HitResult.Great, countGreat }, { HitResult.Ok, countGood ?? 0 }, { HitResult.Meh, countMeh ?? 0 }, - { HitResult.LargeTickMiss, largeTickMisses }, - { HitResult.SliderTailHit, beatmap.HitObjects.Count(x => x is Slider) - sliderTailMisses }, { 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; } protected override double GetAccuracy(IBeatmap beatmap, Dictionary statistics) @@ -137,14 +145,28 @@ protected override double GetAccuracy(IBeatmap beatmap, Dictionary x is Slider); - var countSliderTailHit = statistics[HitResult.SliderTailHit]; - var countLargeTicks = beatmap.HitObjects.Sum(obj => obj.NestedHitObjects.Count(x => x is SliderTick or SliderRepeat)); - var countLargeTickHit = countLargeTicks - statistics[HitResult.LargeTickMiss]; + 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]; - double total = 6 * (countGreat + countGood + countMeh + countMiss) + 3 * countSliders + 0.6 * countLargeTicks; + 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 (6 * countGreat + 2 * countGood + countMeh + 3 * countSliderTailHit + 0.6 * countLargeTickHit) / total; + return total / max; } } } diff --git a/PerformanceCalculator/Simulate/SimulateCommand.cs b/PerformanceCalculator/Simulate/SimulateCommand.cs index c7c31b1c1..be319ad99 100644 --- a/PerformanceCalculator/Simulate/SimulateCommand.cs +++ b/PerformanceCalculator/Simulate/SimulateCommand.cs @@ -63,10 +63,10 @@ public override void Execute() var workingBeatmap = ProcessorWorkingBeatmap.FromFileOrId(Beatmap); var mods = ParseMods(ruleset, Mods, ModOptions); - var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods); + var beatmap = workingBeatmap.GetPlayableBeatmap(ruleset.RulesetInfo); var beatmapMaxCombo = beatmap.GetMaxCombo(); - var statistics = GenerateHitResults(Accuracy / 100, beatmap, Misses, Mehs, Goods); + var statistics = GenerateHitResults(beatmap); var scoreInfo = new ScoreInfo(beatmap.BeatmapInfo, ruleset.RulesetInfo) { Accuracy = GetAccuracy(beatmap, statistics), @@ -83,7 +83,7 @@ public override void Execute() OutputPerformance(scoreInfo, performanceAttributes, difficultyAttributes); } - protected abstract Dictionary GenerateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood); + protected abstract Dictionary GenerateHitResults(IBeatmap beatmap); protected virtual double GetAccuracy(IBeatmap beatmap, Dictionary statistics) => 0; } diff --git a/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs b/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs index 1680f29bb..ac7d69448 100644 --- a/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs +++ b/PerformanceCalculator/Simulate/TaikoSimulateCommand.cs @@ -29,7 +29,9 @@ public class TaikoSimulateCommand : SimulateCommand public override Ruleset Ruleset => new TaikoRuleset(); - protected override Dictionary GenerateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countMeh, int? countGood) + protected override Dictionary GenerateHitResults(IBeatmap beatmap) => generateHitResults(Accuracy / 100, beatmap, Misses, Goods); + + private static Dictionary generateHitResults(double accuracy, IBeatmap beatmap, int countMiss, int? countGood) { var totalResultCount = beatmap.GetMaxCombo(); From 750e377034972f0cd810c41a18d71d4acca63c77 Mon Sep 17 00:00:00 2001 From: Givikap120 Date: Fri, 15 Nov 2024 19:03:18 +0200 Subject: [PATCH 2/2] 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) {