From 67ea3beeb49d5ad74f7dadb9cd9a0396ee9aa299 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 21 Jan 2019 17:53:00 +0900 Subject: [PATCH 1/5] Fix catch slider conversion for last droplets --- .../Objects/JuiceStream.cs | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index d8bd3e0edc..7e8f64d6f7 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -62,15 +62,22 @@ namespace osu.Game.Rulesets.Catch.Objects X = X }); - double lastDropletTime = StartTime; + double lastTickTime = StartTime; for (int span = 0; span < this.SpanCount(); span++) { var spanStartTime = StartTime + span * spanDuration; var reversed = span % 2 == 1; - for (double d = 0; d <= length; d += tickDistance) + for (double d = tickDistance;; d += tickDistance) { + bool isLastTick = false; + if (d + minDistanceFromEnd >= length) + { + d = length; + isLastTick = true; + } + var timeProgress = d / length; var distanceProgress = reversed ? 1 - timeProgress : timeProgress; @@ -79,15 +86,15 @@ namespace osu.Game.Rulesets.Catch.Objects if (LegacyLastTickOffset != null) { // If we're the last tick, apply the legacy offset - if (span == this.SpanCount() - 1 && d + tickDistance > length) + if (span == this.SpanCount() - 1 && isLastTick) time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); } - double tinyTickInterval = time - lastDropletTime; + double tinyTickInterval = time - lastTickTime; while (tinyTickInterval > 100) tinyTickInterval /= 2; - for (double t = lastDropletTime + tinyTickInterval; t < time; t += tinyTickInterval) + for (double t = lastTickTime + tinyTickInterval; t < time; t += tinyTickInterval) { double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; @@ -104,22 +111,22 @@ namespace osu.Game.Rulesets.Catch.Objects }); } - if (d > minDistanceFromEnd && Math.Abs(d - length) > minDistanceFromEnd) - { - AddNested(new Droplet - { - StartTime = time, - X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) - }); - } + lastTickTime = time; - lastDropletTime = time; + if (isLastTick) + break; + + AddNested(new Droplet + { + StartTime = time, + X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, + Samples = new List(Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + })) + }); } AddNested(new Fruit From 3375096f1da60f847ee3ee1161b9d3a490a046fa Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 Jan 2019 18:11:27 +0900 Subject: [PATCH 2/5] Fix juice stream generates tiny droplet at tick time --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 7e8f64d6f7..61beaf7154 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -94,7 +94,8 @@ namespace osu.Game.Rulesets.Catch.Objects while (tinyTickInterval > 100) tinyTickInterval /= 2; - for (double t = lastTickTime + tinyTickInterval; t < time; t += tinyTickInterval) + // we don't want to generate at (t == time - epsilon) due to floating point accuracy. time - 1 seems working. + for (double t = lastTickTime + tinyTickInterval; t < time - 1; t += tinyTickInterval) { double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; From aaba377e113671d078b14b9fedf0e9f3ff9876fa Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 25 Jan 2019 18:13:14 +0900 Subject: [PATCH 3/5] Add a test for catch slider conversion --- .../CatchBeatmapConversionTest.cs | 1 + .../Beatmaps/slider-expected-conversion.json | 1 + .../Resources/Testing/Beatmaps/slider.osu | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json create mode 100644 osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu diff --git a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs index 162624da57..2b7d414555 100644 --- a/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs +++ b/osu.Game.Rulesets.Catch.Tests/CatchBeatmapConversionTest.cs @@ -21,6 +21,7 @@ namespace osu.Game.Rulesets.Catch.Tests [TestCase("basic")] [TestCase("spinner")] [TestCase("spinner-and-circles")] + [TestCase("slider")] public new void Test(string name) { base.Test(name); diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json new file mode 100644 index 0000000000..58c52b6867 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider-expected-conversion.json @@ -0,0 +1 @@ +{"Mappings":[{"StartTime":19184.0,"Objects":[{"StartTime":19184.0,"Position":320.0},{"StartTime":19263.0,"Position":311.730255},{"StartTime":19343.0,"Position":324.6205},{"StartTime":19423.0,"Position":343.0907},{"StartTime":19503.0,"Position":372.2917},{"StartTime":19582.0,"Position":385.194733},{"StartTime":19662.0,"Position":379.0426},{"StartTime":19742.0,"Position":385.1066},{"StartTime":19822.0,"Position":391.624664},{"StartTime":19919.0,"Position":386.27832},{"StartTime":20016.0,"Position":380.117035},{"StartTime":20113.0,"Position":381.664154},{"StartTime":20247.0,"Position":370.872864}]}]} \ No newline at end of file diff --git a/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu new file mode 100644 index 0000000000..d48b2d7769 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Resources/Testing/Beatmaps/slider.osu @@ -0,0 +1,18 @@ +osu file format v14 + +[General] +Mode: 2 + +[Difficulty] +HPDrainRate:3 +CircleSize:2 +OverallDifficulty:4 +ApproachRate:4 +SliderMultiplier:0.9 +SliderTickRate:1 + +[TimingPoints] +35.4473684210527,638.298947368422,4,2,1,60,1,0 + +[HitObjects] +320,176,19184,2,8,P|384:168|368:232,1,150 From 1a5a23875201f033f922cd7b8f770032c93ed0cd Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sat, 26 Jan 2019 16:14:37 +0900 Subject: [PATCH 4/5] Use integer count for tiny droplet generation --- osu.Game.Rulesets.Catch/Objects/JuiceStream.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 61beaf7154..8cbd824805 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -90,13 +90,17 @@ namespace osu.Game.Rulesets.Catch.Objects time = Math.Max(StartTime + Duration / 2, time - LegacyLastTickOffset.Value); } + int tinyTickCount = 1; double tinyTickInterval = time - lastTickTime; - while (tinyTickInterval > 100) - tinyTickInterval /= 2; - - // we don't want to generate at (t == time - epsilon) due to floating point accuracy. time - 1 seems working. - for (double t = lastTickTime + tinyTickInterval; t < time - 1; t += tinyTickInterval) + while (tinyTickInterval > 100 && tinyTickCount < 10000) { + tinyTickInterval /= 2; + tinyTickCount *= 2; + } + + for (int tinyTickIndex = 0; tinyTickIndex < tinyTickCount - 1; tinyTickIndex++) + { + var t = lastTickTime + (tinyTickIndex + 1) * tinyTickInterval; double progress = reversed ? 1 - (t - spanStartTime) / spanDuration : (t - spanStartTime) / spanDuration; AddNested(new TinyDroplet From ea48d6a88a7e1caaecbdfa684b9e8c8f2b093f86 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Sat, 26 Jan 2019 16:16:49 +0900 Subject: [PATCH 5/5] reduce code duplication / allocations --- .../Objects/JuiceStream.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs index 8cbd824805..88b96aa0c4 100644 --- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs +++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs @@ -55,6 +55,13 @@ namespace osu.Game.Rulesets.Catch.Objects var minDistanceFromEnd = Velocity * 0.01; + var tickSamples = Samples.Select(s => new SampleInfo + { + Bank = s.Bank, + Name = @"slidertick", + Volume = s.Volume + }).ToList(); + AddNested(new Fruit { Samples = Samples, @@ -107,12 +114,7 @@ namespace osu.Game.Rulesets.Catch.Objects { StartTime = t, X = X + Path.PositionAt(progress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) + Samples = tickSamples }); } @@ -125,12 +127,7 @@ namespace osu.Game.Rulesets.Catch.Objects { StartTime = time, X = X + Path.PositionAt(distanceProgress).X / CatchPlayfield.BASE_WIDTH, - Samples = new List(Samples.Select(s => new SampleInfo - { - Bank = s.Bank, - Name = @"slidertick", - Volume = s.Volume - })) + Samples = tickSamples }); }