From 49c36787d7d1365c6eda1fcae9b4fb5e77b496de Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:22:57 +0900 Subject: [PATCH 1/7] Remove triangle pattern and remove not-implemented reading strain --- .../Preprocessing/OsuDifficultyBeatmap.cs | 58 ++----------------- .../Preprocessing/OsuDifficultyHitObject.cs | 19 +++--- 2 files changed, 11 insertions(+), 66 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs index 5c8ab0f3d4..867a11f280 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyBeatmap.cs @@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing public class OsuDifficultyBeatmap : IEnumerable { private readonly IEnumerator difficultyObjects; - private readonly Queue onScreen = new Queue(); /// /// Creates an enumerator, which preprocesses a list of s recieved as input, wrapping them as @@ -30,65 +29,16 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing /// /// Returns an enumerator that enumerates all s in the . - /// The inner loop adds objects that appear on screen into a queue until we need to hit the next object. - /// The outer loop returns objects from this queue one at a time, only after they had to be hit, and should no longer be on screen. - /// This means that we can loop through every object that is on screen at the time when a new one appears, - /// allowing us to determine a reading strain for the object that just appeared. /// - public IEnumerator GetEnumerator() - { - while (true) - { - // Add upcoming objects to the queue until we have at least one object that had been hit and can be dequeued. - // This means there is always at least one object in the queue unless we reached the end of the map. - do - { - if (!difficultyObjects.MoveNext()) - break; // New objects can't be added anymore, but we still need to dequeue and return the ones already on screen. - - OsuDifficultyHitObject latest = difficultyObjects.Current; - // Calculate flow values here - - foreach (OsuDifficultyHitObject h in onScreen) - { - // ReSharper disable once PossibleNullReferenceException (resharper not smart enough to understand IEnumerator.MoveNext()) - h.TimeUntilHit -= latest.DeltaTime; - // Calculate reading strain here - } - - onScreen.Enqueue(latest); - } - while (onScreen.Peek().TimeUntilHit > 0); // Keep adding new objects on screen while there is still time before we have to hit the next one. - - if (onScreen.Count == 0) break; // We have reached the end of the map and enumerated all the objects. - yield return onScreen.Dequeue(); // Remove and return objects one by one that had to be hit before the latest one appeared. - } - } - + public IEnumerator GetEnumerator() => difficultyObjects; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); private IEnumerator createDifficultyObjectEnumerator(List objects, double timeRate) { - // We will process OsuHitObjects in groups of three to form a triangle, so we can calculate an angle for each object. - OsuHitObject[] triangle = new OsuHitObject[3]; - - // OsuDifficultyHitObject construction requires three components, an extra copy of the first OsuHitObject is used at the beginning. - if (objects.Count > 1) - { - triangle[1] = objects[0]; // This copy will get shifted to the last spot in the triangle. - triangle[0] = objects[0]; // This component corresponds to the real first OsuHitOject. - } - - // The final component of the first triangle will be the second OsuHitOject of the map, which forms the first jump. + // The first jump is formed by the first two hitobjects of the map. // If the map has less than two OsuHitObjects, the enumerator will not return anything. - for (int i = 1; i < objects.Count; ++i) - { - triangle[2] = triangle[1]; - triangle[1] = triangle[0]; - triangle[0] = objects[i]; - - yield return new OsuDifficultyHitObject(triangle, timeRate); - } + for (int i = 1; i < objects.Count; i++) + yield return new OsuDifficultyHitObject(objects[i], objects[i - 1], timeRate); } } } diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index 415f76ced8..c096e9a464 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -28,26 +28,22 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing /// public double DeltaTime { get; private set; } - /// - /// Number of milliseconds until the has to be hit. - /// - public double TimeUntilHit { get; set; } private const int normalized_radius = 52; + private readonly OsuHitObject lastObject; private readonly double timeRate; - private readonly OsuHitObject[] t; - /// /// Initializes the object calculating extra data required for difficulty calculation. /// - public OsuDifficultyHitObject(OsuHitObject[] triangle, double timeRate) + public OsuDifficultyHitObject(OsuHitObject currentObject, OsuHitObject lastObject, double timeRate) { + this.lastObject = lastObject; this.timeRate = timeRate; - t = triangle; - BaseObject = t[0]; + BaseObject = currentObject; + setDistances(); setTimingValues(); // Calculate angle here @@ -63,10 +59,10 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = t[1].StackedPosition; + Vector2 lastCursorPosition = lastObject.StackedPosition; float lastTravelDistance = 0; - var lastSlider = t[1] as Slider; + var lastSlider = lastObject as Slider; if (lastSlider != null) { computeSliderCursorPosition(lastSlider); @@ -81,7 +77,6 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing { // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure. DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate); - TimeUntilHit = 450; // BaseObject.PreEmpt; } private void computeSliderCursorPosition(Slider slider) From 1b5c151e0edf7f528ca344516f47977908f04a75 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:25:02 +0900 Subject: [PATCH 2/7] Fix DeltaTime being capped incorrectly --- .../OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index c096e9a464..d06518df53 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing private void setTimingValues() { // Every timing inverval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure. - DeltaTime = Math.Max(40, (t[0].StartTime - t[1].StartTime) / timeRate); + DeltaTime = Math.Max(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate); } private void computeSliderCursorPosition(Slider slider) From 1acfc1bbabf365c15401b121a6c2f1eab9b46c1f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:25:20 +0900 Subject: [PATCH 3/7] Fix ModHardRock not properly clamping Drain/OD --- osu.Game/Rulesets/Mods/ModHardRock.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs index 090bc737dd..1629945c87 100644 --- a/osu.Game/Rulesets/Mods/ModHardRock.cs +++ b/osu.Game/Rulesets/Mods/ModHardRock.cs @@ -21,8 +21,8 @@ namespace osu.Game.Rulesets.Mods const float ratio = 1.4f; difficulty.CircleSize *= 1.3f; // CS uses a custom 1.3 ratio. difficulty.ApproachRate = Math.Min(difficulty.ApproachRate * ratio, 10.0f); - difficulty.DrainRate *= ratio; - difficulty.OverallDifficulty *= ratio; + difficulty.DrainRate = Math.Min(difficulty.DrainRate * ratio, 10.0f); + difficulty.OverallDifficulty = Math.Min(difficulty.OverallDifficulty * ratio, 10.0f); } } } From bc197a88e17f745344efd688f65e520d1f814565 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:25:33 +0900 Subject: [PATCH 4/7] Fix slider length calculation including slider head --- .../OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs index d06518df53..1624b936c8 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -102,7 +102,8 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty.Preprocessing } }); - var scoringTimes = slider.NestedHitObjects.Select(t => t.StartTime); + // Skip the head circle + var scoringTimes = slider.NestedHitObjects.Skip(1).Select(t => t.StartTime); foreach (var time in scoringTimes) computeVertex(time); computeVertex(slider.EndTime); From 22f3bee55ae10fa62c0cb7ef9ede89946149529a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:26:06 +0900 Subject: [PATCH 5/7] Fix incorrect iteration over difficulty sections --- .../OsuDifficulty/OsuDifficultyCalculator.cs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs index 4853cd66cd..92cfb77faa 100644 --- a/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/OsuDifficulty/OsuDifficultyCalculator.cs @@ -35,18 +35,22 @@ namespace osu.Game.Rulesets.Osu.OsuDifficulty new Speed() }; - double sectionEnd = section_length / TimeRate; + double sectionLength = section_length * TimeRate; + + // The first object doesn't generate a strain, so we begin with an incremented section end + double currentSectionEnd = 2 * sectionLength; + foreach (OsuDifficultyHitObject h in beatmap) { - while (h.BaseObject.StartTime > sectionEnd) + while (h.BaseObject.StartTime > currentSectionEnd) { foreach (Skill s in skills) { s.SaveCurrentPeak(); - s.StartNewSectionFrom(sectionEnd); + s.StartNewSectionFrom(currentSectionEnd); } - sectionEnd += section_length; + currentSectionEnd += sectionLength; } foreach (Skill s in skills) From cf08293be15de809bf79c3051278babbd164033b Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:44:45 +0900 Subject: [PATCH 6/7] Remove extra newline --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 595e2d7e3e..29de23406b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public class OsuDifficultyHitObject { + private const int normalized_radius = 52; + /// /// The this refers to. /// @@ -28,9 +30,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double DeltaTime { get; private set; } - - private const int normalized_radius = 52; - private readonly OsuHitObject lastObject; private readonly double timeRate; From 3f67d044291d081df01a259aa40e57ff3274fb82 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 May 2018 21:57:08 +0900 Subject: [PATCH 7/7] Cap CS to 10 also --- osu.Game/Rulesets/Mods/ModHardRock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs index 1629945c87..6379be9bfc 100644 --- a/osu.Game/Rulesets/Mods/ModHardRock.cs +++ b/osu.Game/Rulesets/Mods/ModHardRock.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Mods public void ApplyToDifficulty(BeatmapDifficulty difficulty) { const float ratio = 1.4f; - difficulty.CircleSize *= 1.3f; // CS uses a custom 1.3 ratio. + difficulty.CircleSize = Math.Min(difficulty.CircleSize * 1.3f, 10.0f); // CS uses a custom 1.3 ratio. difficulty.ApproachRate = Math.Min(difficulty.ApproachRate * ratio, 10.0f); difficulty.DrainRate = Math.Min(difficulty.DrainRate * ratio, 10.0f); difficulty.OverallDifficulty = Math.Min(difficulty.OverallDifficulty * ratio, 10.0f);