From da976000763e6bcf7975714fa971a08b48777bed Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 16:46:58 +0900 Subject: [PATCH 01/17] Fix inaccurate section lengths for first hitobject --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 5e91ed7a97..028e3acc57 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty 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; + double currentSectionEnd = Math.Ceiling(beatmap.HitObjects.First().StartTime / sectionLength) * sectionLength; foreach (OsuDifficultyHitObject h in difficultyBeatmap) { From 61e7ada977c3567463af8d48a38f7145c2605046 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:36:06 +0900 Subject: [PATCH 02/17] Use ints + fix position calculation --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 29de23406b..7f293fd099 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -88,7 +88,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing var computeVertex = new Action(t => { // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPositionAt(t) - slider.LazyEndPosition.Value; + var diff = slider.StackedPositionAt(((int)t - (int)slider.StartTime) / (float)(int)slider.Duration) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From 1ad5090ad68b52da6a49114c5f5187e200bc05cc Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:37:33 +0900 Subject: [PATCH 03/17] Separate travel distance from jump distance --- .../Preprocessing/OsuDifficultyHitObject.cs | 16 +++++++++++----- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 7f293fd099..2419709e41 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -21,9 +21,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing public OsuHitObject BaseObject { get; } /// - /// Normalized distance from the of the previous . + /// Normalized distance from the end position of the previous . /// - public double Distance { get; private set; } + public double JumpDistance { get; private set; } + + /// + /// Normalized distance from the start position to the end position of the previous . + /// + public double TravelDistance { get; private set; } /// /// Milliseconds elapsed since the StartTime of the previous . @@ -51,10 +56,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing private void setDistances() { // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps. - double scalingFactor = normalized_radius / BaseObject.Radius; + float scalingFactor = normalized_radius / (float)BaseObject.Radius; if (BaseObject.Radius < 30) { - double smallCircleBonus = Math.Min(30 - BaseObject.Radius, 5) / 50; + float smallCircleBonus = Math.Min(30 - (float)BaseObject.Radius, 5) / 50; scalingFactor *= 1 + smallCircleBonus; } @@ -69,7 +74,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - Distance = (lastTravelDistance + (BaseObject.StackedPosition - lastCursorPosition).Length) * scalingFactor; + JumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; + TravelDistance = lastTravelDistance * scalingFactor; } private void setTimingValues() diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 0a45c62671..9ffdd280aa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -14,6 +14,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double SkillMultiplier => 26.25; protected override double StrainDecayBase => 0.15; - protected override double StrainValueOf(OsuDifficultyHitObject current) => Math.Pow(current.Distance, 0.99) / current.DeltaTime; + protected override double StrainValueOf(OsuDifficultyHitObject current) => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.DeltaTime; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index b807f20037..501a8e8e01 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -19,7 +19,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueOf(OsuDifficultyHitObject current) { - double distance = current.Distance; + double distance = current.TravelDistance + current.JumpDistance; double speedValue; if (distance > single_spacing_threshold) From 35f45e74dc2e5e41da3dd186e78652b329610687 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 17:39:10 +0900 Subject: [PATCH 04/17] Calculate scaled positions prior to square-rooting --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 2419709e41..b9eaf9ff04 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.StackedPosition - lastCursorPosition).Length * scalingFactor; + JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; TravelDistance = lastTravelDistance * scalingFactor; } From 0116db95d0363f0ac15932980a307fd7ff458b5f Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 18:37:30 +0900 Subject: [PATCH 05/17] Fix progress calculation --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index b9eaf9ff04..26db2e3faa 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -3,6 +3,7 @@ using System; using System.Linq; +using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using OpenTK; @@ -93,8 +94,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => { + double progress = ((int)t - (int)slider.StartTime) / (float)(int)slider.SpanDuration; + if (progress % 2 > 1) + progress = 1 - progress % 1; + else + progress = progress % 1; + // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPositionAt(((int)t - (int)slider.StartTime) / (float)(int)slider.Duration) - slider.LazyEndPosition.Value; + var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From f8eaccddda1d1b1657127e6ae29778d909904edb Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 8 Oct 2018 18:37:49 +0900 Subject: [PATCH 06/17] Stable doesn't use stacked positions --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 26db2e3faa..44bec47e14 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = lastObject.StackedPosition; + Vector2 lastCursorPosition = lastObject.Position; float lastTravelDistance = 0; var lastSlider = lastObject as Slider; @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; + JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; TravelDistance = lastTravelDistance * scalingFactor; } @@ -89,7 +89,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (slider.LazyEndPosition != null) return; - slider.LazyEndPosition = slider.StackedPosition; + slider.LazyEndPosition = slider.Position; float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => @@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing progress = progress % 1; // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; + var diff = slider.Position + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From b7499fa95627d054e9a3a881420a92808cf12ebe Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 11:34:38 +0900 Subject: [PATCH 07/17] Allow TimingControlPoint to be overridden --- .../Beatmaps/ControlPoints/TimingControlPoint.cs | 2 +- osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs index eb60133fed..81eddaa43a 100644 --- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs +++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs @@ -16,7 +16,7 @@ namespace osu.Game.Beatmaps.ControlPoints /// /// The beat length at this control point. /// - public double BeatLength + public virtual double BeatLength { get => beatLength; set => beatLength = MathHelper.Clamp(value, 6, 60000); diff --git a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs index 181d17932d..5b5bc5d936 100644 --- a/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyBeatmapDecoder.cs @@ -318,12 +318,12 @@ namespace osu.Game.Beatmaps.Formats if (timingChange) { - handleTimingControlPoint(new TimingControlPoint - { - Time = time, - BeatLength = beatLength, - TimeSignature = timeSignature - }); + var controlPoint = CreateTimingControlPoint(); + controlPoint.Time = time; + controlPoint.BeatLength = beatLength; + controlPoint.TimeSignature = timeSignature; + + handleTimingControlPoint(controlPoint); } handleDifficultyControlPoint(new DifficultyControlPoint @@ -418,6 +418,8 @@ namespace osu.Game.Beatmaps.Formats private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0); + protected virtual TimingControlPoint CreateTimingControlPoint() => new TimingControlPoint(); + [Flags] internal enum EffectFlags { From 9facf707be57018b816417d6a8677f5719d87c35 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 11:49:24 +0900 Subject: [PATCH 08/17] Add diffcalc beatmap decoder --- .../Preprocessing/OsuDifficultyHitObject.cs | 1 - ...egacyDifficultyCalculatorBeatmapDecoder.cs | 36 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 44bec47e14..448dc140a3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using osu.Game.Rulesets.Objects.Types; using osu.Game.Rulesets.Osu.Objects; using OpenTK; diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs new file mode 100644 index 0000000000..61efd329c0 --- /dev/null +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2007-2018 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Game.Beatmaps.ControlPoints; + +namespace osu.Game.Beatmaps.Formats +{ + /// + /// A built for difficulty calculation of legacy s + /// + /// To use this, the decoder must be registered by the application through . + /// Doing so will override any existing decoders. + /// + /// + public class LegacyDifficultyCalculatorBeatmapDecoder : LegacyBeatmapDecoder + { + public LegacyDifficultyCalculatorBeatmapDecoder(int version = LATEST_VERSION) + : base(version) + { + } + + public new static void Register() + { + AddDecoder(@"osu file format v", m => new LegacyDifficultyCalculatorBeatmapDecoder(int.Parse(m.Split('v').Last()))); + } + + protected override TimingControlPoint CreateTimingControlPoint() + => new LegacyDifficultyCalculatorControlPoint(); + + private class LegacyDifficultyCalculatorControlPoint : TimingControlPoint + { + public override double BeatLength { get; set; } = 1000; + } + } +} From 0a3be0d253c076bfda1a95ebb26854808be30293 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 9 Oct 2018 12:03:47 +0900 Subject: [PATCH 09/17] Adjust comments slightly --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 448dc140a3..a118d95ff7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -21,12 +21,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing public OsuHitObject BaseObject { get; } /// - /// Normalized distance from the end position of the previous . + /// Normalized distance from the end position of the previous to the start position of this . /// public double JumpDistance { get; private set; } /// - /// Normalized distance from the start position to the end position of the previous . + /// Normalized distance between the start and end position of the previous . /// public double TravelDistance { get; private set; } From d6784c818e02d02c72a86ee3bb5071009b18be63 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 11:49:54 +0900 Subject: [PATCH 10/17] Fix jump/travel distances in some scenarios --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index a118d95ff7..0400f080d9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -74,8 +74,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastTravelDistance = lastSlider.LazyTravelDistance; } - JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; - TravelDistance = lastTravelDistance * scalingFactor; + // Don't need to jump to reach spinners + if (!(BaseObject is Spinner)) + JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; + + // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! + if (BaseObject is Slider) + TravelDistance = lastTravelDistance * scalingFactor; } private void setTimingValues() From 03a95113994fa92d8a296370c373acc0cad65cd7 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:08:46 +0900 Subject: [PATCH 11/17] Apparently stable does use stacking --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 0400f080d9..fd36e85f26 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -63,7 +63,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = lastObject.Position; + Vector2 lastCursorPosition = lastObject.StackedPosition; float lastTravelDistance = 0; var lastSlider = lastObject as Slider; @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) - JumpDistance = (BaseObject.Position * scalingFactor - lastCursorPosition * scalingFactor).Length; + JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! if (BaseObject is Slider) @@ -105,7 +105,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing progress = progress % 1; // ReSharper disable once PossibleInvalidOperationException (bugged in current r# version) - var diff = slider.Position + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; + var diff = slider.StackedPosition + slider.Curve.PositionAt(progress) - slider.LazyEndPosition.Value; float dist = diff.Length; if (dist > approxFollowCircleRadius) From d8f77feddd705e9fc986b4c4ec3b0b3c4472f273 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:52:57 +0900 Subject: [PATCH 12/17] Fix using the wrong slider's travel distance --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index fd36e85f26..1c5b28f407 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -64,23 +64,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing } Vector2 lastCursorPosition = lastObject.StackedPosition; - float lastTravelDistance = 0; var lastSlider = lastObject as Slider; if (lastSlider != null) { computeSliderCursorPosition(lastSlider); lastCursorPosition = lastSlider.LazyEndPosition ?? lastCursorPosition; - lastTravelDistance = lastSlider.LazyTravelDistance; } // Don't need to jump to reach spinners if (!(BaseObject is Spinner)) JumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; - // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also sliders! + // Todo: BUG!!! Last slider's travel distance is considered ONLY IF we ourselves are also a slider! if (BaseObject is Slider) - TravelDistance = lastTravelDistance * scalingFactor; + TravelDistance = (lastSlider?.LazyTravelDistance ?? 0) * scalingFactor; } private void setTimingValues() From 4e37b5c4a7878b11905efd2c4be80ba5e10f33f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 18:53:54 +0900 Subject: [PATCH 13/17] 50ms cap shouldn't be included in the strain decay --- .../Preprocessing/OsuDifficultyHitObject.cs | 11 +++++++++-- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 3 ++- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 1c5b28f407..4905c007b9 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -35,6 +35,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double DeltaTime { get; private set; } + /// + /// Milliseconds elapsed since the start time of the previous , with a minimum of 50ms. + /// + public double StrainTime { get; private set; } + private readonly OsuHitObject lastObject; private readonly double timeRate; @@ -83,8 +88,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.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(50, (BaseObject.StartTime - lastObject.StartTime) / timeRate); + DeltaTime = (BaseObject.StartTime - lastObject.StartTime) / timeRate; + + // Every strain interval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure + StrainTime = Math.Max(50, DeltaTime); } private void computeSliderCursorPosition(Slider slider) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 9ffdd280aa..f11b6d66f6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -14,6 +14,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double SkillMultiplier => 26.25; protected override double StrainDecayBase => 0.15; - protected override double StrainValueOf(OsuDifficultyHitObject current) => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.DeltaTime; + protected override double StrainValueOf(OsuDifficultyHitObject current) + => (Math.Pow(current.TravelDistance, 0.99) + Math.Pow(current.JumpDistance, 0.99)) / current.StrainTime; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 501a8e8e01..1cde03624b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills else speedValue = 0.95; - return speedValue / current.DeltaTime; + return speedValue / current.StrainTime; } } } From f675c939356a9140c7a4e77b7adbbd602f0e986e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 10 Oct 2018 21:37:02 +0900 Subject: [PATCH 14/17] Stably-sort hitobjects --- .../Difficulty/Preprocessing/OsuDifficultyBeatmap.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs index 4443a0e66b..24d4677981 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyBeatmap.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing @@ -23,8 +24,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { // Sort OsuHitObjects by StartTime - they are not correctly ordered in some cases. // This should probably happen before the objects reach the difficulty calculator. - objects.Sort((a, b) => a.StartTime.CompareTo(b.StartTime)); - difficultyObjects = createDifficultyObjectEnumerator(objects, timeRate); + difficultyObjects = createDifficultyObjectEnumerator(objects.OrderBy(h => h.StartTime).ToList(), timeRate); } /// From 7d20efed2c9318b5bd7e1391902714438085a206 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 13:53:29 +0900 Subject: [PATCH 15/17] Fix missing stack position --- .../Difficulty/Preprocessing/OsuDifficultyHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 4905c007b9..ccfcc1ef25 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (slider.LazyEndPosition != null) return; - slider.LazyEndPosition = slider.Position; + slider.LazyEndPosition = slider.StackedPosition; float approxFollowCircleRadius = (float)(slider.Radius * 3); var computeVertex = new Action(t => From 0c4403ef16b17a71208537321b4ed6fd80c3a975 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Thu, 11 Oct 2018 13:53:49 +0900 Subject: [PATCH 16/17] Don't apply version offset during diff calc --- .../Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs index 61efd329c0..13a71aac3d 100644 --- a/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs +++ b/osu.Game/Beatmaps/Formats/LegacyDifficultyCalculatorBeatmapDecoder.cs @@ -18,6 +18,7 @@ namespace osu.Game.Beatmaps.Formats public LegacyDifficultyCalculatorBeatmapDecoder(int version = LATEST_VERSION) : base(version) { + ApplyOffsets = false; } public new static void Register() From 72c8ae8705bae27510e112b311237f3df4ff749a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 12 Oct 2018 16:47:18 +0900 Subject: [PATCH 17/17] Port the old stacking algorithm --- .../Beatmaps/OsuBeatmapProcessor.cs | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs index cfb1b0f050..db80948c94 100644 --- a/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs +++ b/osu.Game.Rulesets.Osu/Beatmaps/OsuBeatmapProcessor.cs @@ -10,6 +10,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps { public class OsuBeatmapProcessor : BeatmapProcessor { + private const int stack_distance = 3; + public OsuBeatmapProcessor(IBeatmap beatmap) : base(beatmap) { @@ -18,17 +20,21 @@ namespace osu.Game.Rulesets.Osu.Beatmaps public override void PostProcess() { base.PostProcess(); - applyStacking((Beatmap)Beatmap); + + var osuBeatmap = (Beatmap)Beatmap; + + // Reset stacking + foreach (var h in osuBeatmap.HitObjects) + h.StackHeight = 0; + + if (Beatmap.BeatmapInfo.BeatmapVersion >= 6) + applyStacking(osuBeatmap); + else + applyStackingOld(osuBeatmap); } private void applyStacking(Beatmap beatmap) { - const int stack_distance = 3; - - // Reset stacking - for (int i = 0; i <= beatmap.HitObjects.Count - 1; i++) - beatmap.HitObjects[i].StackHeight = 0; - // Extend the end index to include objects they are stacked on int extendedEndIndex = beatmap.HitObjects.Count - 1; for (int i = beatmap.HitObjects.Count - 1; i >= 0; i--) @@ -167,5 +173,40 @@ namespace osu.Game.Rulesets.Osu.Beatmaps } } } + + private void applyStackingOld(Beatmap beatmap) + { + for (int i = 0; i < beatmap.HitObjects.Count; i++) + { + OsuHitObject currHitObject = beatmap.HitObjects[i]; + + if (currHitObject.StackHeight != 0 && !(currHitObject is Slider)) + continue; + + double startTime = (currHitObject as IHasEndTime)?.EndTime ?? currHitObject.StartTime; + int sliderStack = 0; + + for (int j = i + 1; j < beatmap.HitObjects.Count; j++) + { + double stackThreshold = beatmap.HitObjects[i].TimePreempt * beatmap.BeatmapInfo.StackLeniency; + + if (beatmap.HitObjects[j].StartTime - stackThreshold > startTime) + break; + + if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.Position) < stack_distance) + { + currHitObject.StackHeight++; + startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; + } + else if (Vector2Extensions.Distance(beatmap.HitObjects[j].Position, currHitObject.EndPosition) < stack_distance) + { + //Case for sliders - bump notes down and right, rather than up and left. + sliderStack++; + beatmap.HitObjects[j].StackHeight -= sliderStack; + startTime = (beatmap.HitObjects[j] as IHasEndTime)?.EndTime ?? beatmap.HitObjects[i].StartTime; + } + } + } + } } }