From fea31cc895b12c91252e611157093f94ad36a7a3 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 22:57:28 +1000 Subject: [PATCH 1/7] introduce effective misscount, accuracy rescale --- .../Difficulty/TaikoPerformanceCalculator.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 2c2dbddf13..9567277a61 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -21,6 +21,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private int countMeh; private int countMiss; + private double effectiveMissCount; + public TaikoPerformanceCalculator() : base(new TaikoRuleset()) { @@ -35,7 +37,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things + // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the misspenalty for shorter object counts lower than 1000, past 1000 is 1:1. + effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + + double multiplier = 1.13; if (score.Mods.Any(m => m is ModHidden)) multiplier *= 1.075; @@ -55,6 +60,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { Difficulty = difficultyValue, Accuracy = accuracyValue, + EffectiveMissCount = effectiveMissCount, Total = totalValue }; } @@ -66,18 +72,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); difficultyValue *= lengthBonus; - difficultyValue *= Math.Pow(0.986, countMiss); + difficultyValue *= Math.Pow(0.986, effectiveMissCount); if (score.Mods.Any(m => m is ModEasy)) - difficultyValue *= 0.980; + difficultyValue *= 0.985; if (score.Mods.Any(m => m is ModHidden)) difficultyValue *= 1.025; + if (score.Mods.Any(m => m is ModHardRock)) + difficultyValue *= 1.050; + if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= 1.05 * lengthBonus; - return difficultyValue * Math.Pow(score.Accuracy, 1.5); + return difficultyValue * Math.Pow(score.Accuracy, 2.0); } private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) @@ -85,18 +94,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (attributes.GreatHitWindow <= 0) return 0; - double accuracyValue = Math.Pow(140.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 12.0) * 27; + double accuracyValue = Math.Pow(60.0 / attributes.GreatHitWindow, 1.1) * Math.Pow(score.Accuracy, 8.0) * Math.Pow(attributes.StarRating, 0.4) * 27.0; double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); accuracyValue *= lengthBonus; - // Slight HDFL Bonus for accuracy. + // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden)) - accuracyValue *= 1.10 * lengthBonus; + accuracyValue *= Math.Max(1.050, 1.075 * lengthBonus); return accuracyValue; } private int totalHits => countGreat + countOk + countMeh + countMiss; + + private int totalSuccessfulHits => countGreat + countOk + countMeh; } } From b30fba143065e6eeefe5a6604df9525e1a4c66b7 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 22:57:40 +1000 Subject: [PATCH 2/7] emc attribute --- .../Difficulty/TaikoPerformanceAttributes.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs index 68d0038b24..b61c13a2df 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs @@ -17,6 +17,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("accuracy")] public double Accuracy { get; set; } + [JsonProperty("effective_miss_count")] + public double EffectiveMissCount { get; set; } + public override IEnumerable GetAttributesForDisplay() { foreach (var attribute in base.GetAttributesForDisplay()) From faf143b11aab5c7a1783fe624b84fecd2f0cf30e Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 23:15:38 +1000 Subject: [PATCH 3/7] fix comment --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 9567277a61..bc745da0fe 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the misspenalty for shorter object counts lower than 1000, past 1000 is 1:1. + // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; double multiplier = 1.13; From c1da5091191bfac75eb2b5b3294f58addd1b64a5 Mon Sep 17 00:00:00 2001 From: Jay L Date: Fri, 19 Aug 2022 23:23:40 +1000 Subject: [PATCH 4/7] round numerical value this is painfully annoying me --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index bc745da0fe..7b0aa47ba5 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= 1.050; if (score.Mods.Any(m => m is ModFlashlight)) - difficultyValue *= 1.05 * lengthBonus; + difficultyValue *= 1.050 * lengthBonus; return difficultyValue * Math.Pow(score.Accuracy, 2.0); } From 3acbcac4d1a215bb0e17ebb36c3f93309d018cb0 Mon Sep 17 00:00:00 2001 From: Jay L Date: Mon, 22 Aug 2022 19:45:51 +1000 Subject: [PATCH 5/7] fix NaN PP on 0 object count --- .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 7b0aa47ba5..6b1ea58129 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. - effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + effectiveMissCount = Math.Max(1.0, Math.Min(0, 1000.0 / totalSuccessfulHits)) * countMiss; double multiplier = 1.13; From 8eab36f8c9ccb0d14ccdd554a2afb95da2d32789 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 25 Aug 2022 14:02:10 +0900 Subject: [PATCH 6/7] Actually fix possible NaN value --- .../Difficulty/TaikoPerformanceCalculator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6b1ea58129..95a1e8bc66 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -38,7 +38,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. - effectiveMissCount = Math.Max(1.0, Math.Min(0, 1000.0 / totalSuccessfulHits)) * countMiss; + if (totalSuccessfulHits > 0) + effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; double multiplier = 1.13; From 1032b2a68c8b1d16b98dc7997d81d4c0d2db2baf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 25 Aug 2022 14:03:25 +0900 Subject: [PATCH 7/7] Fix some `BeatmapCarousel` tests not correctly reinitialising local data per run Closes https://github.com/ppy/osu/issues/19949. --- .../SongSelect/TestSceneBeatmapCarousel.cs | 125 ++++++++++++------ 1 file changed, 84 insertions(+), 41 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs index bb9e83a21c..c3e485d56b 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs @@ -244,8 +244,12 @@ namespace osu.Game.Tests.Visual.SongSelect const int total_set_count = 200; - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo()); + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + for (int i = 0; i < total_set_count; i++) + sets.Add(TestResources.CreateTestBeatmapSetInfo()); + }); loadBeatmaps(sets); @@ -275,8 +279,12 @@ namespace osu.Game.Tests.Visual.SongSelect const int total_set_count = 20; - for (int i = 0; i < total_set_count; i++) - sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + AddStep("Populuate beatmap sets", () => + { + sets.Clear(); + for (int i = 0; i < total_set_count; i++) + sets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + }); loadBeatmaps(sets); @@ -493,18 +501,23 @@ namespace osu.Game.Tests.Visual.SongSelect const string zzz_string = "zzzzz"; - for (int i = 0; i < 20; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(); + sets.Clear(); - if (i == 4) - set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); + for (int i = 0; i < 20; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(); - if (i == 16) - set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_string); + if (i == 4) + set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string); - sets.Add(set); - } + if (i == 16) + set.Beatmaps.ForEach(b => b.Metadata.Author.Username = zzz_string); + + sets.Add(set); + } + }); loadBeatmaps(sets); @@ -521,21 +534,27 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStability() { var sets = new List(); + int idOffset = 0; - for (int i = 0; i < 10; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(); + sets.Clear(); - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); + for (int i = 0; i < 10; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(); - beatmap.Metadata.Artist = $"artist {i / 2}"; - beatmap.Metadata.Title = $"title {9 - i}"; + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); - sets.Add(set); - } + beatmap.Metadata.Artist = $"artist {i / 2}"; + beatmap.Metadata.Title = $"title {9 - i}"; - int idOffset = sets.First().OnlineID; + sets.Add(set); + } + + idOffset = sets.First().OnlineID; + }); loadBeatmaps(sets); @@ -556,26 +575,32 @@ namespace osu.Game.Tests.Visual.SongSelect public void TestSortingStabilityWithNewItems() { List sets = new List(); + int idOffset = 0; - for (int i = 0; i < 3; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(3); + sets.Clear(); - // only need to set the first as they are a shared reference. - var beatmap = set.Beatmaps.First(); + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); - beatmap.Metadata.Artist = "same artist"; - beatmap.Metadata.Title = "same title"; + // only need to set the first as they are a shared reference. + var beatmap = set.Beatmaps.First(); - sets.Add(set); - } + beatmap.Metadata.Artist = "same artist"; + beatmap.Metadata.Title = "same title"; - int idOffset = sets.First().OnlineID; + sets.Add(set); + } + + idOffset = sets.First().OnlineID; + }); loadBeatmaps(sets); AddStep("Sort by artist", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Artist }, false)); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); AddStep("Add new item", () => { @@ -590,10 +615,16 @@ namespace osu.Game.Tests.Visual.SongSelect carousel.UpdateBeatmapSet(set); }); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); AddStep("Sort by title", () => carousel.Filter(new FilterCriteria { Sort = SortMode.Title }, false)); - AddAssert("Items remain in original order", () => carousel.BeatmapSets.Select((set, index) => set.OnlineID == idOffset + index).All(b => b)); + assertOriginalOrderMaintained(); + + void assertOriginalOrderMaintained() + { + AddAssert("Items remain in original order", + () => carousel.BeatmapSets.Select(s => s.OnlineID), () => Is.EqualTo(carousel.BeatmapSets.Select((set, index) => idOffset + index))); + } } [Test] @@ -601,13 +632,18 @@ namespace osu.Game.Tests.Visual.SongSelect { List sets = new List(); - for (int i = 0; i < 3; i++) + AddStep("Populuate beatmap sets", () => { - var set = TestResources.CreateTestBeatmapSetInfo(3); - set.Beatmaps[0].StarRating = 3 - i; - set.Beatmaps[2].StarRating = 6 + i; - sets.Add(set); - } + sets.Clear(); + + for (int i = 0; i < 3; i++) + { + var set = TestResources.CreateTestBeatmapSetInfo(3); + set.Beatmaps[0].StarRating = 3 - i; + set.Beatmaps[2].StarRating = 6 + i; + sets.Add(set); + } + }); loadBeatmaps(sets); @@ -759,8 +795,13 @@ namespace osu.Game.Tests.Visual.SongSelect { List manySets = new List(); - for (int i = 1; i <= 50; i++) - manySets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + AddStep("Populuate beatmap sets", () => + { + manySets.Clear(); + + for (int i = 1; i <= 50; i++) + manySets.Add(TestResources.CreateTestBeatmapSetInfo(3)); + }); loadBeatmaps(manySets); @@ -791,6 +832,8 @@ namespace osu.Game.Tests.Visual.SongSelect AddStep("populate maps", () => { + manySets.Clear(); + for (int i = 0; i < 10; i++) { manySets.Add(TestResources.CreateTestBeatmapSetInfo(3, new[]